Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drivers: clk: Add ZynqMP clock driver

This patch adds CCF compliant clock driver for ZynqMP.
Clock driver queries supported clock information from
firmware and regiters pll and output clocks with CCF.

Signed-off-by: Rajan Vaja <rajan.vaja@xilinx.com>
Signed-off-by: Tejas Patel <tejasp@xilinx.com>
Signed-off-by: Shubhrajyoti Datta <shubhrajyoti.datta@xilinx.com>
Signed-off-by: Jolly Shah <jolly.shah@xilinx.com>
Acked-by: Olof Johansson <olof@lixom.net>
Reviewed-by: Stephen Boyd <sboyd@kernel.org>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>

authored by

Jolly Shah and committed by
Michal Simek
3fde0e16 26372d09

+1638
+1
drivers/clk/Kconfig
··· 299 299 source "drivers/clk/tegra/Kconfig" 300 300 source "drivers/clk/ti/Kconfig" 301 301 source "drivers/clk/uniphier/Kconfig" 302 + source "drivers/clk/zynqmp/Kconfig" 302 303 303 304 endmenu
+1
drivers/clk/Makefile
··· 108 108 endif 109 109 obj-$(CONFIG_ARCH_ZX) += zte/ 110 110 obj-$(CONFIG_ARCH_ZYNQ) += zynq/ 111 + obj-$(CONFIG_COMMON_CLK_ZYNQMP) += zynqmp/
+10
drivers/clk/zynqmp/Kconfig
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + 3 + config COMMON_CLK_ZYNQMP 4 + bool "Support for Xilinx ZynqMP Ultrascale+ clock controllers" 5 + depends on ARCH_ZYNQMP || COMPILE_TEST 6 + depends on ZYNQMP_FIRMWARE 7 + help 8 + Support for the Zynqmp Ultrascale clock controller. 9 + It has a dependency on the PMU firmware. 10 + Say Y if you want to include clock support.
+4
drivers/clk/zynqmp/Makefile
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + # Zynq Ultrascale+ MPSoC clock specific Makefile 3 + 4 + obj-$(CONFIG_ARCH_ZYNQMP) += pll.o clk-gate-zynqmp.o divider.o clk-mux-zynqmp.o clkc.o
+144
drivers/clk/zynqmp/clk-gate-zynqmp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Zynq UltraScale+ MPSoC clock controller 4 + * 5 + * Copyright (C) 2016-2018 Xilinx 6 + * 7 + * Gated clock implementation 8 + */ 9 + 10 + #include <linux/clk-provider.h> 11 + #include <linux/slab.h> 12 + #include "clk-zynqmp.h" 13 + 14 + /** 15 + * struct clk_gate - gating clock 16 + * @hw: handle between common and hardware-specific interfaces 17 + * @flags: hardware-specific flags 18 + * @clk_id: Id of clock 19 + */ 20 + struct zynqmp_clk_gate { 21 + struct clk_hw hw; 22 + u8 flags; 23 + u32 clk_id; 24 + }; 25 + 26 + #define to_zynqmp_clk_gate(_hw) container_of(_hw, struct zynqmp_clk_gate, hw) 27 + 28 + /** 29 + * zynqmp_clk_gate_enable() - Enable clock 30 + * @hw: handle between common and hardware-specific interfaces 31 + * 32 + * Return: 0 on success else error code 33 + */ 34 + static int zynqmp_clk_gate_enable(struct clk_hw *hw) 35 + { 36 + struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); 37 + const char *clk_name = clk_hw_get_name(hw); 38 + u32 clk_id = gate->clk_id; 39 + int ret; 40 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 41 + 42 + ret = eemi_ops->clock_enable(clk_id); 43 + 44 + if (ret) 45 + pr_warn_once("%s() clock enabled failed for %s, ret = %d\n", 46 + __func__, clk_name, ret); 47 + 48 + return ret; 49 + } 50 + 51 + /* 52 + * zynqmp_clk_gate_disable() - Disable clock 53 + * @hw: handle between common and hardware-specific interfaces 54 + */ 55 + static void zynqmp_clk_gate_disable(struct clk_hw *hw) 56 + { 57 + struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); 58 + const char *clk_name = clk_hw_get_name(hw); 59 + u32 clk_id = gate->clk_id; 60 + int ret; 61 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 62 + 63 + ret = eemi_ops->clock_disable(clk_id); 64 + 65 + if (ret) 66 + pr_warn_once("%s() clock disable failed for %s, ret = %d\n", 67 + __func__, clk_name, ret); 68 + } 69 + 70 + /** 71 + * zynqmp_clk_gate_is_enable() - Check clock state 72 + * @hw: handle between common and hardware-specific interfaces 73 + * 74 + * Return: 1 if enabled, 0 if disabled else error code 75 + */ 76 + static int zynqmp_clk_gate_is_enabled(struct clk_hw *hw) 77 + { 78 + struct zynqmp_clk_gate *gate = to_zynqmp_clk_gate(hw); 79 + const char *clk_name = clk_hw_get_name(hw); 80 + u32 clk_id = gate->clk_id; 81 + int state, ret; 82 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 83 + 84 + ret = eemi_ops->clock_getstate(clk_id, &state); 85 + if (ret) { 86 + pr_warn_once("%s() clock get state failed for %s, ret = %d\n", 87 + __func__, clk_name, ret); 88 + return -EIO; 89 + } 90 + 91 + return state ? 1 : 0; 92 + } 93 + 94 + static const struct clk_ops zynqmp_clk_gate_ops = { 95 + .enable = zynqmp_clk_gate_enable, 96 + .disable = zynqmp_clk_gate_disable, 97 + .is_enabled = zynqmp_clk_gate_is_enabled, 98 + }; 99 + 100 + /** 101 + * zynqmp_clk_register_gate() - Register a gate clock with the clock framework 102 + * @name: Name of this clock 103 + * @clk_id: Id of this clock 104 + * @parents: Name of this clock's parents 105 + * @num_parents: Number of parents 106 + * @nodes: Clock topology node 107 + * 108 + * Return: clock hardware of the registered clock gate 109 + */ 110 + struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id, 111 + const char * const *parents, 112 + u8 num_parents, 113 + const struct clock_topology *nodes) 114 + { 115 + struct zynqmp_clk_gate *gate; 116 + struct clk_hw *hw; 117 + int ret; 118 + struct clk_init_data init; 119 + 120 + /* allocate the gate */ 121 + gate = kzalloc(sizeof(*gate), GFP_KERNEL); 122 + if (!gate) 123 + return ERR_PTR(-ENOMEM); 124 + 125 + init.name = name; 126 + init.ops = &zynqmp_clk_gate_ops; 127 + init.flags = nodes->flag; 128 + init.parent_names = parents; 129 + init.num_parents = 1; 130 + 131 + /* struct clk_gate assignments */ 132 + gate->flags = nodes->type_flag; 133 + gate->hw.init = &init; 134 + gate->clk_id = clk_id; 135 + 136 + hw = &gate->hw; 137 + ret = clk_hw_register(NULL, hw); 138 + if (ret) { 139 + kfree(gate); 140 + hw = ERR_PTR(ret); 141 + } 142 + 143 + return hw; 144 + }
+141
drivers/clk/zynqmp/clk-mux-zynqmp.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Zynq UltraScale+ MPSoC mux 4 + * 5 + * Copyright (C) 2016-2018 Xilinx 6 + */ 7 + 8 + #include <linux/clk-provider.h> 9 + #include <linux/slab.h> 10 + #include "clk-zynqmp.h" 11 + 12 + /* 13 + * DOC: basic adjustable multiplexer clock that cannot gate 14 + * 15 + * Traits of this clock: 16 + * prepare - clk_prepare only ensures that parents are prepared 17 + * enable - clk_enable only ensures that parents are enabled 18 + * rate - rate is only affected by parent switching. No clk_set_rate support 19 + * parent - parent is adjustable through clk_set_parent 20 + */ 21 + 22 + /** 23 + * struct zynqmp_clk_mux - multiplexer clock 24 + * 25 + * @hw: handle between common and hardware-specific interfaces 26 + * @flags: hardware-specific flags 27 + * @clk_id: Id of clock 28 + */ 29 + struct zynqmp_clk_mux { 30 + struct clk_hw hw; 31 + u8 flags; 32 + u32 clk_id; 33 + }; 34 + 35 + #define to_zynqmp_clk_mux(_hw) container_of(_hw, struct zynqmp_clk_mux, hw) 36 + 37 + /** 38 + * zynqmp_clk_mux_get_parent() - Get parent of clock 39 + * @hw: handle between common and hardware-specific interfaces 40 + * 41 + * Return: Parent index 42 + */ 43 + static u8 zynqmp_clk_mux_get_parent(struct clk_hw *hw) 44 + { 45 + struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw); 46 + const char *clk_name = clk_hw_get_name(hw); 47 + u32 clk_id = mux->clk_id; 48 + u32 val; 49 + int ret; 50 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 51 + 52 + ret = eemi_ops->clock_getparent(clk_id, &val); 53 + 54 + if (ret) 55 + pr_warn_once("%s() getparent failed for clock: %s, ret = %d\n", 56 + __func__, clk_name, ret); 57 + 58 + return val; 59 + } 60 + 61 + /** 62 + * zynqmp_clk_mux_set_parent() - Set parent of clock 63 + * @hw: handle between common and hardware-specific interfaces 64 + * @index: Parent index 65 + * 66 + * Return: 0 on success else error+reason 67 + */ 68 + static int zynqmp_clk_mux_set_parent(struct clk_hw *hw, u8 index) 69 + { 70 + struct zynqmp_clk_mux *mux = to_zynqmp_clk_mux(hw); 71 + const char *clk_name = clk_hw_get_name(hw); 72 + u32 clk_id = mux->clk_id; 73 + int ret; 74 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 75 + 76 + ret = eemi_ops->clock_setparent(clk_id, index); 77 + 78 + if (ret) 79 + pr_warn_once("%s() set parent failed for clock: %s, ret = %d\n", 80 + __func__, clk_name, ret); 81 + 82 + return ret; 83 + } 84 + 85 + static const struct clk_ops zynqmp_clk_mux_ops = { 86 + .get_parent = zynqmp_clk_mux_get_parent, 87 + .set_parent = zynqmp_clk_mux_set_parent, 88 + .determine_rate = __clk_mux_determine_rate, 89 + }; 90 + 91 + static const struct clk_ops zynqmp_clk_mux_ro_ops = { 92 + .get_parent = zynqmp_clk_mux_get_parent, 93 + }; 94 + 95 + /** 96 + * zynqmp_clk_register_mux() - Register a mux table with the clock 97 + * framework 98 + * @name: Name of this clock 99 + * @clk_id: Id of this clock 100 + * @parents: Name of this clock's parents 101 + * @num_parents: Number of parents 102 + * @nodes: Clock topology node 103 + * 104 + * Return: clock hardware of the registered clock mux 105 + */ 106 + struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id, 107 + const char * const *parents, 108 + u8 num_parents, 109 + const struct clock_topology *nodes) 110 + { 111 + struct zynqmp_clk_mux *mux; 112 + struct clk_hw *hw; 113 + struct clk_init_data init; 114 + int ret; 115 + 116 + mux = kzalloc(sizeof(*mux), GFP_KERNEL); 117 + if (!mux) 118 + return ERR_PTR(-ENOMEM); 119 + 120 + init.name = name; 121 + if (nodes->type_flag & CLK_MUX_READ_ONLY) 122 + init.ops = &zynqmp_clk_mux_ro_ops; 123 + else 124 + init.ops = &zynqmp_clk_mux_ops; 125 + init.flags = nodes->flag; 126 + init.parent_names = parents; 127 + init.num_parents = num_parents; 128 + mux->flags = nodes->type_flag; 129 + mux->hw.init = &init; 130 + mux->clk_id = clk_id; 131 + 132 + hw = &mux->hw; 133 + ret = clk_hw_register(NULL, hw); 134 + if (ret) { 135 + kfree(hw); 136 + hw = ERR_PTR(ret); 137 + } 138 + 139 + return hw; 140 + } 141 + EXPORT_SYMBOL_GPL(zynqmp_clk_register_mux);
+68
drivers/clk/zynqmp/clk-zynqmp.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Copyright (C) 2016-2018 Xilinx 4 + */ 5 + 6 + #ifndef __LINUX_CLK_ZYNQMP_H_ 7 + #define __LINUX_CLK_ZYNQMP_H_ 8 + 9 + #include <linux/spinlock.h> 10 + 11 + #include <linux/firmware/xlnx-zynqmp.h> 12 + 13 + /* Clock APIs payload parameters */ 14 + #define CLK_GET_NAME_RESP_LEN 16 15 + #define CLK_GET_TOPOLOGY_RESP_WORDS 3 16 + #define CLK_GET_PARENTS_RESP_WORDS 3 17 + #define CLK_GET_ATTR_RESP_WORDS 1 18 + 19 + enum topology_type { 20 + TYPE_INVALID, 21 + TYPE_MUX, 22 + TYPE_PLL, 23 + TYPE_FIXEDFACTOR, 24 + TYPE_DIV1, 25 + TYPE_DIV2, 26 + TYPE_GATE, 27 + }; 28 + 29 + /** 30 + * struct clock_topology - Clock topology 31 + * @type: Type of topology 32 + * @flag: Topology flags 33 + * @type_flag: Topology type specific flag 34 + */ 35 + struct clock_topology { 36 + u32 type; 37 + u32 flag; 38 + u32 type_flag; 39 + }; 40 + 41 + struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id, 42 + const char * const *parents, 43 + u8 num_parents, 44 + const struct clock_topology *nodes); 45 + 46 + struct clk_hw *zynqmp_clk_register_gate(const char *name, u32 clk_id, 47 + const char * const *parents, 48 + u8 num_parents, 49 + const struct clock_topology *nodes); 50 + 51 + struct clk_hw *zynqmp_clk_register_divider(const char *name, 52 + u32 clk_id, 53 + const char * const *parents, 54 + u8 num_parents, 55 + const struct clock_topology *nodes); 56 + 57 + struct clk_hw *zynqmp_clk_register_mux(const char *name, u32 clk_id, 58 + const char * const *parents, 59 + u8 num_parents, 60 + const struct clock_topology *nodes); 61 + 62 + struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, 63 + u32 clk_id, 64 + const char * const *parents, 65 + u8 num_parents, 66 + const struct clock_topology *nodes); 67 + 68 + #endif
+716
drivers/clk/zynqmp/clkc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Zynq UltraScale+ MPSoC clock controller 4 + * 5 + * Copyright (C) 2016-2018 Xilinx 6 + * 7 + * Based on drivers/clk/zynq/clkc.c 8 + */ 9 + 10 + #include <linux/bitfield.h> 11 + #include <linux/clk.h> 12 + #include <linux/clk-provider.h> 13 + #include <linux/module.h> 14 + #include <linux/of_platform.h> 15 + #include <linux/slab.h> 16 + #include <linux/string.h> 17 + 18 + #include "clk-zynqmp.h" 19 + 20 + #define MAX_PARENT 100 21 + #define MAX_NODES 6 22 + #define MAX_NAME_LEN 50 23 + 24 + #define CLK_TYPE_SHIFT 2 25 + 26 + #define PM_API_PAYLOAD_LEN 3 27 + 28 + #define NA_PARENT 0xFFFFFFFF 29 + #define DUMMY_PARENT 0xFFFFFFFE 30 + 31 + #define CLK_TYPE_FIELD_LEN 4 32 + #define CLK_TOPOLOGY_NODE_OFFSET 16 33 + #define NODES_PER_RESP 3 34 + 35 + #define CLK_TYPE_FIELD_MASK 0xF 36 + #define CLK_FLAG_FIELD_MASK GENMASK(21, 8) 37 + #define CLK_TYPE_FLAG_FIELD_MASK GENMASK(31, 24) 38 + 39 + #define CLK_PARENTS_ID_LEN 16 40 + #define CLK_PARENTS_ID_MASK 0xFFFF 41 + 42 + /* Flags for parents */ 43 + #define PARENT_CLK_SELF 0 44 + #define PARENT_CLK_NODE1 1 45 + #define PARENT_CLK_NODE2 2 46 + #define PARENT_CLK_NODE3 3 47 + #define PARENT_CLK_NODE4 4 48 + #define PARENT_CLK_EXTERNAL 5 49 + 50 + #define END_OF_CLK_NAME "END_OF_CLK" 51 + #define END_OF_TOPOLOGY_NODE 1 52 + #define END_OF_PARENTS 1 53 + #define RESERVED_CLK_NAME "" 54 + 55 + #define CLK_VALID_MASK 0x1 56 + 57 + enum clk_type { 58 + CLK_TYPE_OUTPUT, 59 + CLK_TYPE_EXTERNAL, 60 + }; 61 + 62 + /** 63 + * struct clock_parent - Clock parent 64 + * @name: Parent name 65 + * @id: Parent clock ID 66 + * @flag: Parent flags 67 + */ 68 + struct clock_parent { 69 + char name[MAX_NAME_LEN]; 70 + int id; 71 + u32 flag; 72 + }; 73 + 74 + /** 75 + * struct zynqmp_clock - Clock 76 + * @clk_name: Clock name 77 + * @valid: Validity flag of clock 78 + * @type: Clock type (Output/External) 79 + * @node: Clock topology nodes 80 + * @num_nodes: Number of nodes present in topology 81 + * @parent: Parent of clock 82 + * @num_parents: Number of parents of clock 83 + */ 84 + struct zynqmp_clock { 85 + char clk_name[MAX_NAME_LEN]; 86 + u32 valid; 87 + enum clk_type type; 88 + struct clock_topology node[MAX_NODES]; 89 + u32 num_nodes; 90 + struct clock_parent parent[MAX_PARENT]; 91 + u32 num_parents; 92 + }; 93 + 94 + static const char clk_type_postfix[][10] = { 95 + [TYPE_INVALID] = "", 96 + [TYPE_MUX] = "_mux", 97 + [TYPE_GATE] = "", 98 + [TYPE_DIV1] = "_div1", 99 + [TYPE_DIV2] = "_div2", 100 + [TYPE_FIXEDFACTOR] = "_ff", 101 + [TYPE_PLL] = "" 102 + }; 103 + 104 + static struct clk_hw *(* const clk_topology[]) (const char *name, u32 clk_id, 105 + const char * const *parents, 106 + u8 num_parents, 107 + const struct clock_topology *nodes) 108 + = { 109 + [TYPE_INVALID] = NULL, 110 + [TYPE_MUX] = zynqmp_clk_register_mux, 111 + [TYPE_PLL] = zynqmp_clk_register_pll, 112 + [TYPE_FIXEDFACTOR] = zynqmp_clk_register_fixed_factor, 113 + [TYPE_DIV1] = zynqmp_clk_register_divider, 114 + [TYPE_DIV2] = zynqmp_clk_register_divider, 115 + [TYPE_GATE] = zynqmp_clk_register_gate 116 + }; 117 + 118 + static struct zynqmp_clock *clock; 119 + static struct clk_hw_onecell_data *zynqmp_data; 120 + static unsigned int clock_max_idx; 121 + static const struct zynqmp_eemi_ops *eemi_ops; 122 + 123 + /** 124 + * zynqmp_is_valid_clock() - Check whether clock is valid or not 125 + * @clk_id: Clock index 126 + * 127 + * Return: 1 if clock is valid, 0 if clock is invalid else error code 128 + */ 129 + static inline int zynqmp_is_valid_clock(u32 clk_id) 130 + { 131 + if (clk_id > clock_max_idx) 132 + return -ENODEV; 133 + 134 + return clock[clk_id].valid; 135 + } 136 + 137 + /** 138 + * zynqmp_get_clock_name() - Get name of clock from Clock index 139 + * @clk_id: Clock index 140 + * @clk_name: Name of clock 141 + * 142 + * Return: 0 on success else error code 143 + */ 144 + static int zynqmp_get_clock_name(u32 clk_id, char *clk_name) 145 + { 146 + int ret; 147 + 148 + ret = zynqmp_is_valid_clock(clk_id); 149 + if (ret == 1) { 150 + strncpy(clk_name, clock[clk_id].clk_name, MAX_NAME_LEN); 151 + return 0; 152 + } 153 + 154 + return ret == 0 ? -EINVAL : ret; 155 + } 156 + 157 + /** 158 + * zynqmp_get_clock_type() - Get type of clock 159 + * @clk_id: Clock index 160 + * @type: Clock type: CLK_TYPE_OUTPUT or CLK_TYPE_EXTERNAL 161 + * 162 + * Return: 0 on success else error code 163 + */ 164 + static int zynqmp_get_clock_type(u32 clk_id, u32 *type) 165 + { 166 + int ret; 167 + 168 + ret = zynqmp_is_valid_clock(clk_id); 169 + if (ret == 1) { 170 + *type = clock[clk_id].type; 171 + return 0; 172 + } 173 + 174 + return ret == 0 ? -EINVAL : ret; 175 + } 176 + 177 + /** 178 + * zynqmp_pm_clock_get_num_clocks() - Get number of clocks in system 179 + * @nclocks: Number of clocks in system/board. 180 + * 181 + * Call firmware API to get number of clocks. 182 + * 183 + * Return: 0 on success else error code. 184 + */ 185 + static int zynqmp_pm_clock_get_num_clocks(u32 *nclocks) 186 + { 187 + struct zynqmp_pm_query_data qdata = {0}; 188 + u32 ret_payload[PAYLOAD_ARG_CNT]; 189 + int ret; 190 + 191 + qdata.qid = PM_QID_CLOCK_GET_NUM_CLOCKS; 192 + 193 + ret = eemi_ops->query_data(qdata, ret_payload); 194 + *nclocks = ret_payload[1]; 195 + 196 + return ret; 197 + } 198 + 199 + /** 200 + * zynqmp_pm_clock_get_name() - Get the name of clock for given id 201 + * @clock_id: ID of the clock to be queried 202 + * @name: Name of given clock 203 + * 204 + * This function is used to get name of clock specified by given 205 + * clock ID. 206 + * 207 + * Return: Returns 0, in case of error name would be 0 208 + */ 209 + static int zynqmp_pm_clock_get_name(u32 clock_id, char *name) 210 + { 211 + struct zynqmp_pm_query_data qdata = {0}; 212 + u32 ret_payload[PAYLOAD_ARG_CNT]; 213 + 214 + qdata.qid = PM_QID_CLOCK_GET_NAME; 215 + qdata.arg1 = clock_id; 216 + 217 + eemi_ops->query_data(qdata, ret_payload); 218 + memcpy(name, ret_payload, CLK_GET_NAME_RESP_LEN); 219 + 220 + return 0; 221 + } 222 + 223 + /** 224 + * zynqmp_pm_clock_get_topology() - Get the topology of clock for given id 225 + * @clock_id: ID of the clock to be queried 226 + * @index: Node index of clock topology 227 + * @topology: Buffer to store nodes in topology and flags 228 + * 229 + * This function is used to get topology information for the clock 230 + * specified by given clock ID. 231 + * 232 + * This API will return 3 node of topology with a single response. To get 233 + * other nodes, master should call same API in loop with new 234 + * index till error is returned. E.g First call should have 235 + * index 0 which will return nodes 0,1 and 2. Next call, index 236 + * should be 3 which will return nodes 3,4 and 5 and so on. 237 + * 238 + * Return: 0 on success else error+reason 239 + */ 240 + static int zynqmp_pm_clock_get_topology(u32 clock_id, u32 index, u32 *topology) 241 + { 242 + struct zynqmp_pm_query_data qdata = {0}; 243 + u32 ret_payload[PAYLOAD_ARG_CNT]; 244 + int ret; 245 + 246 + qdata.qid = PM_QID_CLOCK_GET_TOPOLOGY; 247 + qdata.arg1 = clock_id; 248 + qdata.arg2 = index; 249 + 250 + ret = eemi_ops->query_data(qdata, ret_payload); 251 + memcpy(topology, &ret_payload[1], CLK_GET_TOPOLOGY_RESP_WORDS * 4); 252 + 253 + return ret; 254 + } 255 + 256 + /** 257 + * zynqmp_clk_register_fixed_factor() - Register fixed factor with the 258 + * clock framework 259 + * @name: Name of this clock 260 + * @clk_id: Clock ID 261 + * @parents: Name of this clock's parents 262 + * @num_parents: Number of parents 263 + * @nodes: Clock topology node 264 + * 265 + * Return: clock hardware to the registered clock 266 + */ 267 + struct clk_hw *zynqmp_clk_register_fixed_factor(const char *name, u32 clk_id, 268 + const char * const *parents, 269 + u8 num_parents, 270 + const struct clock_topology *nodes) 271 + { 272 + u32 mult, div; 273 + struct clk_hw *hw; 274 + struct zynqmp_pm_query_data qdata = {0}; 275 + u32 ret_payload[PAYLOAD_ARG_CNT]; 276 + int ret; 277 + 278 + qdata.qid = PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS; 279 + qdata.arg1 = clk_id; 280 + 281 + ret = eemi_ops->query_data(qdata, ret_payload); 282 + mult = ret_payload[1]; 283 + div = ret_payload[2]; 284 + 285 + hw = clk_hw_register_fixed_factor(NULL, name, 286 + parents[0], 287 + nodes->flag, mult, 288 + div); 289 + 290 + return hw; 291 + } 292 + 293 + /** 294 + * zynqmp_pm_clock_get_parents() - Get the first 3 parents of clock for given id 295 + * @clock_id: Clock ID 296 + * @index: Parent index 297 + * @parents: 3 parents of the given clock 298 + * 299 + * This function is used to get 3 parents for the clock specified by 300 + * given clock ID. 301 + * 302 + * This API will return 3 parents with a single response. To get 303 + * other parents, master should call same API in loop with new 304 + * parent index till error is returned. E.g First call should have 305 + * index 0 which will return parents 0,1 and 2. Next call, index 306 + * should be 3 which will return parent 3,4 and 5 and so on. 307 + * 308 + * Return: 0 on success else error+reason 309 + */ 310 + static int zynqmp_pm_clock_get_parents(u32 clock_id, u32 index, u32 *parents) 311 + { 312 + struct zynqmp_pm_query_data qdata = {0}; 313 + u32 ret_payload[PAYLOAD_ARG_CNT]; 314 + int ret; 315 + 316 + qdata.qid = PM_QID_CLOCK_GET_PARENTS; 317 + qdata.arg1 = clock_id; 318 + qdata.arg2 = index; 319 + 320 + ret = eemi_ops->query_data(qdata, ret_payload); 321 + memcpy(parents, &ret_payload[1], CLK_GET_PARENTS_RESP_WORDS * 4); 322 + 323 + return ret; 324 + } 325 + 326 + /** 327 + * zynqmp_pm_clock_get_attributes() - Get the attributes of clock for given id 328 + * @clock_id: Clock ID 329 + * @attr: Clock attributes 330 + * 331 + * This function is used to get clock's attributes(e.g. valid, clock type, etc). 332 + * 333 + * Return: 0 on success else error+reason 334 + */ 335 + static int zynqmp_pm_clock_get_attributes(u32 clock_id, u32 *attr) 336 + { 337 + struct zynqmp_pm_query_data qdata = {0}; 338 + u32 ret_payload[PAYLOAD_ARG_CNT]; 339 + int ret; 340 + 341 + qdata.qid = PM_QID_CLOCK_GET_ATTRIBUTES; 342 + qdata.arg1 = clock_id; 343 + 344 + ret = eemi_ops->query_data(qdata, ret_payload); 345 + memcpy(attr, &ret_payload[1], CLK_GET_ATTR_RESP_WORDS * 4); 346 + 347 + return ret; 348 + } 349 + 350 + /** 351 + * __zynqmp_clock_get_topology() - Get topology data of clock from firmware 352 + * response data 353 + * @topology: Clock topology 354 + * @data: Clock topology data received from firmware 355 + * @nnodes: Number of nodes 356 + * 357 + * Return: 0 on success else error+reason 358 + */ 359 + static int __zynqmp_clock_get_topology(struct clock_topology *topology, 360 + u32 *data, u32 *nnodes) 361 + { 362 + int i; 363 + 364 + for (i = 0; i < PM_API_PAYLOAD_LEN; i++) { 365 + if (!(data[i] & CLK_TYPE_FIELD_MASK)) 366 + return END_OF_TOPOLOGY_NODE; 367 + topology[*nnodes].type = data[i] & CLK_TYPE_FIELD_MASK; 368 + topology[*nnodes].flag = FIELD_GET(CLK_FLAG_FIELD_MASK, 369 + data[i]); 370 + topology[*nnodes].type_flag = 371 + FIELD_GET(CLK_TYPE_FLAG_FIELD_MASK, data[i]); 372 + (*nnodes)++; 373 + } 374 + 375 + return 0; 376 + } 377 + 378 + /** 379 + * zynqmp_clock_get_topology() - Get topology of clock from firmware using 380 + * PM_API 381 + * @clk_id: Clock index 382 + * @topology: Clock topology 383 + * @num_nodes: Number of nodes 384 + * 385 + * Return: 0 on success else error+reason 386 + */ 387 + static int zynqmp_clock_get_topology(u32 clk_id, 388 + struct clock_topology *topology, 389 + u32 *num_nodes) 390 + { 391 + int j, ret; 392 + u32 pm_resp[PM_API_PAYLOAD_LEN] = {0}; 393 + 394 + *num_nodes = 0; 395 + for (j = 0; j <= MAX_NODES; j += 3) { 396 + ret = zynqmp_pm_clock_get_topology(clk_id, j, pm_resp); 397 + if (ret) 398 + return ret; 399 + ret = __zynqmp_clock_get_topology(topology, pm_resp, num_nodes); 400 + if (ret == END_OF_TOPOLOGY_NODE) 401 + return 0; 402 + } 403 + 404 + return 0; 405 + } 406 + 407 + /** 408 + * __zynqmp_clock_get_topology() - Get parents info of clock from firmware 409 + * response data 410 + * @parents: Clock parents 411 + * @data: Clock parents data received from firmware 412 + * @nparent: Number of parent 413 + * 414 + * Return: 0 on success else error+reason 415 + */ 416 + static int __zynqmp_clock_get_parents(struct clock_parent *parents, u32 *data, 417 + u32 *nparent) 418 + { 419 + int i; 420 + struct clock_parent *parent; 421 + 422 + for (i = 0; i < PM_API_PAYLOAD_LEN; i++) { 423 + if (data[i] == NA_PARENT) 424 + return END_OF_PARENTS; 425 + 426 + parent = &parents[i]; 427 + parent->id = data[i] & CLK_PARENTS_ID_MASK; 428 + if (data[i] == DUMMY_PARENT) { 429 + strcpy(parent->name, "dummy_name"); 430 + parent->flag = 0; 431 + } else { 432 + parent->flag = data[i] >> CLK_PARENTS_ID_LEN; 433 + if (zynqmp_get_clock_name(parent->id, parent->name)) 434 + continue; 435 + } 436 + *nparent += 1; 437 + } 438 + 439 + return 0; 440 + } 441 + 442 + /** 443 + * zynqmp_clock_get_parents() - Get parents info from firmware using PM_API 444 + * @clk_id: Clock index 445 + * @parents: Clock parents 446 + * @num_parents: Total number of parents 447 + * 448 + * Return: 0 on success else error+reason 449 + */ 450 + static int zynqmp_clock_get_parents(u32 clk_id, struct clock_parent *parents, 451 + u32 *num_parents) 452 + { 453 + int j = 0, ret; 454 + u32 pm_resp[PM_API_PAYLOAD_LEN] = {0}; 455 + 456 + *num_parents = 0; 457 + do { 458 + /* Get parents from firmware */ 459 + ret = zynqmp_pm_clock_get_parents(clk_id, j, pm_resp); 460 + if (ret) 461 + return ret; 462 + 463 + ret = __zynqmp_clock_get_parents(&parents[j], pm_resp, 464 + num_parents); 465 + if (ret == END_OF_PARENTS) 466 + return 0; 467 + j += PM_API_PAYLOAD_LEN; 468 + } while (*num_parents <= MAX_PARENT); 469 + 470 + return 0; 471 + } 472 + 473 + /** 474 + * zynqmp_get_parent_list() - Create list of parents name 475 + * @np: Device node 476 + * @clk_id: Clock index 477 + * @parent_list: List of parent's name 478 + * @num_parents: Total number of parents 479 + * 480 + * Return: 0 on success else error+reason 481 + */ 482 + static int zynqmp_get_parent_list(struct device_node *np, u32 clk_id, 483 + const char **parent_list, u32 *num_parents) 484 + { 485 + int i = 0, ret; 486 + u32 total_parents = clock[clk_id].num_parents; 487 + struct clock_topology *clk_nodes; 488 + struct clock_parent *parents; 489 + 490 + clk_nodes = clock[clk_id].node; 491 + parents = clock[clk_id].parent; 492 + 493 + for (i = 0; i < total_parents; i++) { 494 + if (!parents[i].flag) { 495 + parent_list[i] = parents[i].name; 496 + } else if (parents[i].flag == PARENT_CLK_EXTERNAL) { 497 + ret = of_property_match_string(np, "clock-names", 498 + parents[i].name); 499 + if (ret < 0) 500 + strcpy(parents[i].name, "dummy_name"); 501 + parent_list[i] = parents[i].name; 502 + } else { 503 + strcat(parents[i].name, 504 + clk_type_postfix[clk_nodes[parents[i].flag - 1]. 505 + type]); 506 + parent_list[i] = parents[i].name; 507 + } 508 + } 509 + 510 + *num_parents = total_parents; 511 + return 0; 512 + } 513 + 514 + /** 515 + * zynqmp_register_clk_topology() - Register clock topology 516 + * @clk_id: Clock index 517 + * @clk_name: Clock Name 518 + * @num_parents: Total number of parents 519 + * @parent_names: List of parents name 520 + * 521 + * Return: Returns either clock hardware or error+reason 522 + */ 523 + static struct clk_hw *zynqmp_register_clk_topology(int clk_id, char *clk_name, 524 + int num_parents, 525 + const char **parent_names) 526 + { 527 + int j; 528 + u32 num_nodes; 529 + char *clk_out = NULL; 530 + struct clock_topology *nodes; 531 + struct clk_hw *hw = NULL; 532 + 533 + nodes = clock[clk_id].node; 534 + num_nodes = clock[clk_id].num_nodes; 535 + 536 + for (j = 0; j < num_nodes; j++) { 537 + /* 538 + * Clock name received from firmware is output clock name. 539 + * Intermediate clock names are postfixed with type of clock. 540 + */ 541 + if (j != (num_nodes - 1)) { 542 + clk_out = kasprintf(GFP_KERNEL, "%s%s", clk_name, 543 + clk_type_postfix[nodes[j].type]); 544 + } else { 545 + clk_out = kasprintf(GFP_KERNEL, "%s", clk_name); 546 + } 547 + 548 + if (!clk_topology[nodes[j].type]) 549 + continue; 550 + 551 + hw = (*clk_topology[nodes[j].type])(clk_out, clk_id, 552 + parent_names, 553 + num_parents, 554 + &nodes[j]); 555 + if (IS_ERR(hw)) 556 + pr_warn_once("%s() %s register fail with %ld\n", 557 + __func__, clk_name, PTR_ERR(hw)); 558 + 559 + parent_names[0] = clk_out; 560 + } 561 + kfree(clk_out); 562 + return hw; 563 + } 564 + 565 + /** 566 + * zynqmp_register_clocks() - Register clocks 567 + * @np: Device node 568 + * 569 + * Return: 0 on success else error code 570 + */ 571 + static int zynqmp_register_clocks(struct device_node *np) 572 + { 573 + int ret; 574 + u32 i, total_parents = 0, type = 0; 575 + const char *parent_names[MAX_PARENT]; 576 + 577 + for (i = 0; i < clock_max_idx; i++) { 578 + char clk_name[MAX_NAME_LEN]; 579 + 580 + /* get clock name, continue to next clock if name not found */ 581 + if (zynqmp_get_clock_name(i, clk_name)) 582 + continue; 583 + 584 + /* Check if clock is valid and output clock. 585 + * Do not register invalid or external clock. 586 + */ 587 + ret = zynqmp_get_clock_type(i, &type); 588 + if (ret || type != CLK_TYPE_OUTPUT) 589 + continue; 590 + 591 + /* Get parents of clock*/ 592 + if (zynqmp_get_parent_list(np, i, parent_names, 593 + &total_parents)) { 594 + WARN_ONCE(1, "No parents found for %s\n", 595 + clock[i].clk_name); 596 + continue; 597 + } 598 + 599 + zynqmp_data->hws[i] = 600 + zynqmp_register_clk_topology(i, clk_name, 601 + total_parents, 602 + parent_names); 603 + } 604 + 605 + for (i = 0; i < clock_max_idx; i++) { 606 + if (IS_ERR(zynqmp_data->hws[i])) { 607 + pr_err("Zynq Ultrascale+ MPSoC clk %s: register failed with %ld\n", 608 + clock[i].clk_name, PTR_ERR(zynqmp_data->hws[i])); 609 + WARN_ON(1); 610 + } 611 + } 612 + return 0; 613 + } 614 + 615 + /** 616 + * zynqmp_get_clock_info() - Get clock information from firmware using PM_API 617 + */ 618 + static void zynqmp_get_clock_info(void) 619 + { 620 + int i, ret; 621 + u32 attr, type = 0; 622 + 623 + for (i = 0; i < clock_max_idx; i++) { 624 + zynqmp_pm_clock_get_name(i, clock[i].clk_name); 625 + if (!strcmp(clock[i].clk_name, RESERVED_CLK_NAME)) 626 + continue; 627 + 628 + ret = zynqmp_pm_clock_get_attributes(i, &attr); 629 + if (ret) 630 + continue; 631 + 632 + clock[i].valid = attr & CLK_VALID_MASK; 633 + clock[i].type = attr >> CLK_TYPE_SHIFT ? CLK_TYPE_EXTERNAL : 634 + CLK_TYPE_OUTPUT; 635 + } 636 + 637 + /* Get topology of all clock */ 638 + for (i = 0; i < clock_max_idx; i++) { 639 + ret = zynqmp_get_clock_type(i, &type); 640 + if (ret || type != CLK_TYPE_OUTPUT) 641 + continue; 642 + 643 + ret = zynqmp_clock_get_topology(i, clock[i].node, 644 + &clock[i].num_nodes); 645 + if (ret) 646 + continue; 647 + 648 + ret = zynqmp_clock_get_parents(i, clock[i].parent, 649 + &clock[i].num_parents); 650 + if (ret) 651 + continue; 652 + } 653 + } 654 + 655 + /** 656 + * zynqmp_clk_setup() - Setup the clock framework and register clocks 657 + * @np: Device node 658 + * 659 + * Return: 0 on success else error code 660 + */ 661 + static int zynqmp_clk_setup(struct device_node *np) 662 + { 663 + int ret; 664 + 665 + ret = zynqmp_pm_clock_get_num_clocks(&clock_max_idx); 666 + if (ret) 667 + return ret; 668 + 669 + zynqmp_data = kzalloc(sizeof(*zynqmp_data) + sizeof(*zynqmp_data) * 670 + clock_max_idx, GFP_KERNEL); 671 + if (!zynqmp_data) 672 + return -ENOMEM; 673 + 674 + clock = kcalloc(clock_max_idx, sizeof(*clock), GFP_KERNEL); 675 + if (!clock) { 676 + kfree(zynqmp_data); 677 + return -ENOMEM; 678 + } 679 + 680 + zynqmp_get_clock_info(); 681 + zynqmp_register_clocks(np); 682 + 683 + zynqmp_data->num = clock_max_idx; 684 + of_clk_add_hw_provider(np, of_clk_hw_onecell_get, zynqmp_data); 685 + 686 + return 0; 687 + } 688 + 689 + static int zynqmp_clock_probe(struct platform_device *pdev) 690 + { 691 + int ret; 692 + struct device *dev = &pdev->dev; 693 + 694 + eemi_ops = zynqmp_pm_get_eemi_ops(); 695 + if (!eemi_ops) 696 + return -ENXIO; 697 + 698 + ret = zynqmp_clk_setup(dev->of_node); 699 + 700 + return ret; 701 + } 702 + 703 + static const struct of_device_id zynqmp_clock_of_match[] = { 704 + {.compatible = "xlnx,zynqmp-clk"}, 705 + {}, 706 + }; 707 + MODULE_DEVICE_TABLE(of, zynqmp_clock_of_match); 708 + 709 + static struct platform_driver zynqmp_clock_driver = { 710 + .driver = { 711 + .name = "zynqmp_clock", 712 + .of_match_table = zynqmp_clock_of_match, 713 + }, 714 + .probe = zynqmp_clock_probe, 715 + }; 716 + module_platform_driver(zynqmp_clock_driver);
+217
drivers/clk/zynqmp/divider.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Zynq UltraScale+ MPSoC Divider support 4 + * 5 + * Copyright (C) 2016-2018 Xilinx 6 + * 7 + * Adjustable divider clock implementation 8 + */ 9 + 10 + #include <linux/clk.h> 11 + #include <linux/clk-provider.h> 12 + #include <linux/slab.h> 13 + #include "clk-zynqmp.h" 14 + 15 + /* 16 + * DOC: basic adjustable divider clock that cannot gate 17 + * 18 + * Traits of this clock: 19 + * prepare - clk_prepare only ensures that parents are prepared 20 + * enable - clk_enable only ensures that parents are enabled 21 + * rate - rate is adjustable. clk->rate = ceiling(parent->rate / divisor) 22 + * parent - fixed parent. No clk_set_parent support 23 + */ 24 + 25 + #define to_zynqmp_clk_divider(_hw) \ 26 + container_of(_hw, struct zynqmp_clk_divider, hw) 27 + 28 + #define CLK_FRAC BIT(13) /* has a fractional parent */ 29 + 30 + /** 31 + * struct zynqmp_clk_divider - adjustable divider clock 32 + * @hw: handle between common and hardware-specific interfaces 33 + * @flags: Hardware specific flags 34 + * @clk_id: Id of clock 35 + * @div_type: divisor type (TYPE_DIV1 or TYPE_DIV2) 36 + */ 37 + struct zynqmp_clk_divider { 38 + struct clk_hw hw; 39 + u8 flags; 40 + u32 clk_id; 41 + u32 div_type; 42 + }; 43 + 44 + static inline int zynqmp_divider_get_val(unsigned long parent_rate, 45 + unsigned long rate) 46 + { 47 + return DIV_ROUND_CLOSEST(parent_rate, rate); 48 + } 49 + 50 + /** 51 + * zynqmp_clk_divider_recalc_rate() - Recalc rate of divider clock 52 + * @hw: handle between common and hardware-specific interfaces 53 + * @parent_rate: rate of parent clock 54 + * 55 + * Return: 0 on success else error+reason 56 + */ 57 + static unsigned long zynqmp_clk_divider_recalc_rate(struct clk_hw *hw, 58 + unsigned long parent_rate) 59 + { 60 + struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 61 + const char *clk_name = clk_hw_get_name(hw); 62 + u32 clk_id = divider->clk_id; 63 + u32 div_type = divider->div_type; 64 + u32 div, value; 65 + int ret; 66 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 67 + 68 + ret = eemi_ops->clock_getdivider(clk_id, &div); 69 + 70 + if (ret) 71 + pr_warn_once("%s() get divider failed for %s, ret = %d\n", 72 + __func__, clk_name, ret); 73 + 74 + if (div_type == TYPE_DIV1) 75 + value = div & 0xFFFF; 76 + else 77 + value = div >> 16; 78 + 79 + return DIV_ROUND_UP_ULL(parent_rate, value); 80 + } 81 + 82 + /** 83 + * zynqmp_clk_divider_round_rate() - Round rate of divider clock 84 + * @hw: handle between common and hardware-specific interfaces 85 + * @rate: rate of clock to be set 86 + * @prate: rate of parent clock 87 + * 88 + * Return: 0 on success else error+reason 89 + */ 90 + static long zynqmp_clk_divider_round_rate(struct clk_hw *hw, 91 + unsigned long rate, 92 + unsigned long *prate) 93 + { 94 + struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 95 + const char *clk_name = clk_hw_get_name(hw); 96 + u32 clk_id = divider->clk_id; 97 + u32 div_type = divider->div_type; 98 + u32 bestdiv; 99 + int ret; 100 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 101 + 102 + /* if read only, just return current value */ 103 + if (divider->flags & CLK_DIVIDER_READ_ONLY) { 104 + ret = eemi_ops->clock_getdivider(clk_id, &bestdiv); 105 + 106 + if (ret) 107 + pr_warn_once("%s() get divider failed for %s, ret = %d\n", 108 + __func__, clk_name, ret); 109 + if (div_type == TYPE_DIV1) 110 + bestdiv = bestdiv & 0xFFFF; 111 + else 112 + bestdiv = bestdiv >> 16; 113 + 114 + return DIV_ROUND_UP_ULL((u64)*prate, bestdiv); 115 + } 116 + 117 + bestdiv = zynqmp_divider_get_val(*prate, rate); 118 + 119 + if ((clk_hw_get_flags(hw) & CLK_SET_RATE_PARENT) && 120 + (divider->flags & CLK_FRAC)) 121 + bestdiv = rate % *prate ? 1 : bestdiv; 122 + *prate = rate * bestdiv; 123 + 124 + return rate; 125 + } 126 + 127 + /** 128 + * zynqmp_clk_divider_set_rate() - Set rate of divider clock 129 + * @hw: handle between common and hardware-specific interfaces 130 + * @rate: rate of clock to be set 131 + * @parent_rate: rate of parent clock 132 + * 133 + * Return: 0 on success else error+reason 134 + */ 135 + static int zynqmp_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate, 136 + unsigned long parent_rate) 137 + { 138 + struct zynqmp_clk_divider *divider = to_zynqmp_clk_divider(hw); 139 + const char *clk_name = clk_hw_get_name(hw); 140 + u32 clk_id = divider->clk_id; 141 + u32 div_type = divider->div_type; 142 + u32 value, div; 143 + int ret; 144 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 145 + 146 + value = zynqmp_divider_get_val(parent_rate, rate); 147 + if (div_type == TYPE_DIV1) { 148 + div = value & 0xFFFF; 149 + div |= 0xffff << 16; 150 + } else { 151 + div = 0xffff; 152 + div |= value << 16; 153 + } 154 + 155 + ret = eemi_ops->clock_setdivider(clk_id, div); 156 + 157 + if (ret) 158 + pr_warn_once("%s() set divider failed for %s, ret = %d\n", 159 + __func__, clk_name, ret); 160 + 161 + return ret; 162 + } 163 + 164 + static const struct clk_ops zynqmp_clk_divider_ops = { 165 + .recalc_rate = zynqmp_clk_divider_recalc_rate, 166 + .round_rate = zynqmp_clk_divider_round_rate, 167 + .set_rate = zynqmp_clk_divider_set_rate, 168 + }; 169 + 170 + /** 171 + * zynqmp_clk_register_divider() - Register a divider clock 172 + * @name: Name of this clock 173 + * @clk_id: Id of clock 174 + * @parents: Name of this clock's parents 175 + * @num_parents: Number of parents 176 + * @nodes: Clock topology node 177 + * 178 + * Return: clock hardware to registered clock divider 179 + */ 180 + struct clk_hw *zynqmp_clk_register_divider(const char *name, 181 + u32 clk_id, 182 + const char * const *parents, 183 + u8 num_parents, 184 + const struct clock_topology *nodes) 185 + { 186 + struct zynqmp_clk_divider *div; 187 + struct clk_hw *hw; 188 + struct clk_init_data init; 189 + int ret; 190 + 191 + /* allocate the divider */ 192 + div = kzalloc(sizeof(*div), GFP_KERNEL); 193 + if (!div) 194 + return ERR_PTR(-ENOMEM); 195 + 196 + init.name = name; 197 + init.ops = &zynqmp_clk_divider_ops; 198 + init.flags = nodes->flag; 199 + init.parent_names = parents; 200 + init.num_parents = 1; 201 + 202 + /* struct clk_divider assignments */ 203 + div->flags = nodes->type_flag; 204 + div->hw.init = &init; 205 + div->clk_id = clk_id; 206 + div->div_type = nodes->type; 207 + 208 + hw = &div->hw; 209 + ret = clk_hw_register(NULL, hw); 210 + if (ret) { 211 + kfree(div); 212 + hw = ERR_PTR(ret); 213 + } 214 + 215 + return hw; 216 + } 217 + EXPORT_SYMBOL_GPL(zynqmp_clk_register_divider);
+335
drivers/clk/zynqmp/pll.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Zynq UltraScale+ MPSoC PLL driver 4 + * 5 + * Copyright (C) 2016-2018 Xilinx 6 + */ 7 + 8 + #include <linux/clk.h> 9 + #include <linux/clk-provider.h> 10 + #include <linux/slab.h> 11 + #include "clk-zynqmp.h" 12 + 13 + /** 14 + * struct zynqmp_pll - PLL clock 15 + * @hw: Handle between common and hardware-specific interfaces 16 + * @clk_id: PLL clock ID 17 + */ 18 + struct zynqmp_pll { 19 + struct clk_hw hw; 20 + u32 clk_id; 21 + }; 22 + 23 + #define to_zynqmp_pll(_hw) container_of(_hw, struct zynqmp_pll, hw) 24 + 25 + #define PLL_FBDIV_MIN 25 26 + #define PLL_FBDIV_MAX 125 27 + 28 + #define PS_PLL_VCO_MIN 1500000000 29 + #define PS_PLL_VCO_MAX 3000000000UL 30 + 31 + enum pll_mode { 32 + PLL_MODE_INT, 33 + PLL_MODE_FRAC, 34 + }; 35 + 36 + #define FRAC_OFFSET 0x8 37 + #define PLLFCFG_FRAC_EN BIT(31) 38 + #define FRAC_DIV BIT(16) /* 2^16 */ 39 + 40 + /** 41 + * zynqmp_pll_get_mode() - Get mode of PLL 42 + * @hw: Handle between common and hardware-specific interfaces 43 + * 44 + * Return: Mode of PLL 45 + */ 46 + static inline enum pll_mode zynqmp_pll_get_mode(struct clk_hw *hw) 47 + { 48 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 49 + u32 clk_id = clk->clk_id; 50 + const char *clk_name = clk_hw_get_name(hw); 51 + u32 ret_payload[PAYLOAD_ARG_CNT]; 52 + int ret; 53 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 54 + 55 + ret = eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_MODE, clk_id, 0, 56 + ret_payload); 57 + if (ret) 58 + pr_warn_once("%s() PLL get frac mode failed for %s, ret = %d\n", 59 + __func__, clk_name, ret); 60 + 61 + return ret_payload[1]; 62 + } 63 + 64 + /** 65 + * zynqmp_pll_set_mode() - Set the PLL mode 66 + * @hw: Handle between common and hardware-specific interfaces 67 + * @on: Flag to determine the mode 68 + */ 69 + static inline void zynqmp_pll_set_mode(struct clk_hw *hw, bool on) 70 + { 71 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 72 + u32 clk_id = clk->clk_id; 73 + const char *clk_name = clk_hw_get_name(hw); 74 + int ret; 75 + u32 mode; 76 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 77 + 78 + if (on) 79 + mode = PLL_MODE_FRAC; 80 + else 81 + mode = PLL_MODE_INT; 82 + 83 + ret = eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_MODE, clk_id, mode, NULL); 84 + if (ret) 85 + pr_warn_once("%s() PLL set frac mode failed for %s, ret = %d\n", 86 + __func__, clk_name, ret); 87 + } 88 + 89 + /** 90 + * zynqmp_pll_round_rate() - Round a clock frequency 91 + * @hw: Handle between common and hardware-specific interfaces 92 + * @rate: Desired clock frequency 93 + * @prate: Clock frequency of parent clock 94 + * 95 + * Return: Frequency closest to @rate the hardware can generate 96 + */ 97 + static long zynqmp_pll_round_rate(struct clk_hw *hw, unsigned long rate, 98 + unsigned long *prate) 99 + { 100 + u32 fbdiv; 101 + long rate_div, f; 102 + 103 + /* Enable the fractional mode if needed */ 104 + rate_div = (rate * FRAC_DIV) / *prate; 105 + f = rate_div % FRAC_DIV; 106 + zynqmp_pll_set_mode(hw, !!f); 107 + 108 + if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) { 109 + if (rate > PS_PLL_VCO_MAX) { 110 + fbdiv = rate / PS_PLL_VCO_MAX; 111 + rate = rate / (fbdiv + 1); 112 + } 113 + if (rate < PS_PLL_VCO_MIN) { 114 + fbdiv = DIV_ROUND_UP(PS_PLL_VCO_MIN, rate); 115 + rate = rate * fbdiv; 116 + } 117 + return rate; 118 + } 119 + 120 + fbdiv = DIV_ROUND_CLOSEST(rate, *prate); 121 + fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); 122 + return *prate * fbdiv; 123 + } 124 + 125 + /** 126 + * zynqmp_pll_recalc_rate() - Recalculate clock frequency 127 + * @hw: Handle between common and hardware-specific interfaces 128 + * @parent_rate: Clock frequency of parent clock 129 + * 130 + * Return: Current clock frequency 131 + */ 132 + static unsigned long zynqmp_pll_recalc_rate(struct clk_hw *hw, 133 + unsigned long parent_rate) 134 + { 135 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 136 + u32 clk_id = clk->clk_id; 137 + const char *clk_name = clk_hw_get_name(hw); 138 + u32 fbdiv, data; 139 + unsigned long rate, frac; 140 + u32 ret_payload[PAYLOAD_ARG_CNT]; 141 + int ret; 142 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 143 + 144 + ret = eemi_ops->clock_getdivider(clk_id, &fbdiv); 145 + if (ret) 146 + pr_warn_once("%s() get divider failed for %s, ret = %d\n", 147 + __func__, clk_name, ret); 148 + 149 + rate = parent_rate * fbdiv; 150 + if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) { 151 + eemi_ops->ioctl(0, IOCTL_GET_PLL_FRAC_DATA, clk_id, 0, 152 + ret_payload); 153 + data = ret_payload[1]; 154 + frac = (parent_rate * data) / FRAC_DIV; 155 + rate = rate + frac; 156 + } 157 + 158 + return rate; 159 + } 160 + 161 + /** 162 + * zynqmp_pll_set_rate() - Set rate of PLL 163 + * @hw: Handle between common and hardware-specific interfaces 164 + * @rate: Frequency of clock to be set 165 + * @parent_rate: Clock frequency of parent clock 166 + * 167 + * Set PLL divider to set desired rate. 168 + * 169 + * Returns: rate which is set on success else error code 170 + */ 171 + static int zynqmp_pll_set_rate(struct clk_hw *hw, unsigned long rate, 172 + unsigned long parent_rate) 173 + { 174 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 175 + u32 clk_id = clk->clk_id; 176 + const char *clk_name = clk_hw_get_name(hw); 177 + u32 fbdiv; 178 + long rate_div, frac, m, f; 179 + int ret; 180 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 181 + 182 + if (zynqmp_pll_get_mode(hw) == PLL_MODE_FRAC) { 183 + rate_div = (rate * FRAC_DIV) / parent_rate; 184 + m = rate_div / FRAC_DIV; 185 + f = rate_div % FRAC_DIV; 186 + m = clamp_t(u32, m, (PLL_FBDIV_MIN), (PLL_FBDIV_MAX)); 187 + rate = parent_rate * m; 188 + frac = (parent_rate * f) / FRAC_DIV; 189 + 190 + ret = eemi_ops->clock_setdivider(clk_id, m); 191 + if (ret) 192 + pr_warn_once("%s() set divider failed for %s, ret = %d\n", 193 + __func__, clk_name, ret); 194 + 195 + eemi_ops->ioctl(0, IOCTL_SET_PLL_FRAC_DATA, clk_id, f, NULL); 196 + 197 + return rate + frac; 198 + } 199 + 200 + fbdiv = DIV_ROUND_CLOSEST(rate, parent_rate); 201 + fbdiv = clamp_t(u32, fbdiv, PLL_FBDIV_MIN, PLL_FBDIV_MAX); 202 + ret = eemi_ops->clock_setdivider(clk_id, fbdiv); 203 + if (ret) 204 + pr_warn_once("%s() set divider failed for %s, ret = %d\n", 205 + __func__, clk_name, ret); 206 + 207 + return parent_rate * fbdiv; 208 + } 209 + 210 + /** 211 + * zynqmp_pll_is_enabled() - Check if a clock is enabled 212 + * @hw: Handle between common and hardware-specific interfaces 213 + * 214 + * Return: 1 if the clock is enabled, 0 otherwise 215 + */ 216 + static int zynqmp_pll_is_enabled(struct clk_hw *hw) 217 + { 218 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 219 + const char *clk_name = clk_hw_get_name(hw); 220 + u32 clk_id = clk->clk_id; 221 + unsigned int state; 222 + int ret; 223 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 224 + 225 + ret = eemi_ops->clock_getstate(clk_id, &state); 226 + if (ret) { 227 + pr_warn_once("%s() clock get state failed for %s, ret = %d\n", 228 + __func__, clk_name, ret); 229 + return -EIO; 230 + } 231 + 232 + return state ? 1 : 0; 233 + } 234 + 235 + /** 236 + * zynqmp_pll_enable() - Enable clock 237 + * @hw: Handle between common and hardware-specific interfaces 238 + * 239 + * Return: 0 on success else error code 240 + */ 241 + static int zynqmp_pll_enable(struct clk_hw *hw) 242 + { 243 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 244 + const char *clk_name = clk_hw_get_name(hw); 245 + u32 clk_id = clk->clk_id; 246 + int ret; 247 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 248 + 249 + if (zynqmp_pll_is_enabled(hw)) 250 + return 0; 251 + 252 + ret = eemi_ops->clock_enable(clk_id); 253 + if (ret) 254 + pr_warn_once("%s() clock enable failed for %s, ret = %d\n", 255 + __func__, clk_name, ret); 256 + 257 + return ret; 258 + } 259 + 260 + /** 261 + * zynqmp_pll_disable() - Disable clock 262 + * @hw: Handle between common and hardware-specific interfaces 263 + */ 264 + static void zynqmp_pll_disable(struct clk_hw *hw) 265 + { 266 + struct zynqmp_pll *clk = to_zynqmp_pll(hw); 267 + const char *clk_name = clk_hw_get_name(hw); 268 + u32 clk_id = clk->clk_id; 269 + int ret; 270 + const struct zynqmp_eemi_ops *eemi_ops = zynqmp_pm_get_eemi_ops(); 271 + 272 + if (!zynqmp_pll_is_enabled(hw)) 273 + return; 274 + 275 + ret = eemi_ops->clock_disable(clk_id); 276 + if (ret) 277 + pr_warn_once("%s() clock disable failed for %s, ret = %d\n", 278 + __func__, clk_name, ret); 279 + } 280 + 281 + static const struct clk_ops zynqmp_pll_ops = { 282 + .enable = zynqmp_pll_enable, 283 + .disable = zynqmp_pll_disable, 284 + .is_enabled = zynqmp_pll_is_enabled, 285 + .round_rate = zynqmp_pll_round_rate, 286 + .recalc_rate = zynqmp_pll_recalc_rate, 287 + .set_rate = zynqmp_pll_set_rate, 288 + }; 289 + 290 + /** 291 + * zynqmp_clk_register_pll() - Register PLL with the clock framework 292 + * @name: PLL name 293 + * @clk_id: Clock ID 294 + * @parents: Name of this clock's parents 295 + * @num_parents: Number of parents 296 + * @nodes: Clock topology node 297 + * 298 + * Return: clock hardware to the registered clock 299 + */ 300 + struct clk_hw *zynqmp_clk_register_pll(const char *name, u32 clk_id, 301 + const char * const *parents, 302 + u8 num_parents, 303 + const struct clock_topology *nodes) 304 + { 305 + struct zynqmp_pll *pll; 306 + struct clk_hw *hw; 307 + struct clk_init_data init; 308 + int ret; 309 + 310 + init.name = name; 311 + init.ops = &zynqmp_pll_ops; 312 + init.flags = nodes->flag; 313 + init.parent_names = parents; 314 + init.num_parents = 1; 315 + 316 + pll = kzalloc(sizeof(*pll), GFP_KERNEL); 317 + if (!pll) 318 + return ERR_PTR(-ENOMEM); 319 + 320 + pll->hw.init = &init; 321 + pll->clk_id = clk_id; 322 + 323 + hw = &pll->hw; 324 + ret = clk_hw_register(NULL, hw); 325 + if (ret) { 326 + kfree(pll); 327 + return ERR_PTR(ret); 328 + } 329 + 330 + clk_hw_set_rate_range(hw, PS_PLL_VCO_MIN, PS_PLL_VCO_MAX); 331 + if (ret < 0) 332 + pr_err("%s:ERROR clk_set_rate_range failed %d\n", name, ret); 333 + 334 + return hw; 335 + }
+1
include/linux/firmware/xlnx-zynqmp.h
··· 72 72 PM_QID_CLOCK_GET_FIXEDFACTOR_PARAMS, 73 73 PM_QID_CLOCK_GET_PARENTS, 74 74 PM_QID_CLOCK_GET_ATTRIBUTES, 75 + PM_QID_CLOCK_GET_NUM_CLOCKS = 12, 75 76 }; 76 77 77 78 /**