1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2019 DENX Software Engineering
4  * Lukasz Majewski, DENX Software Engineering, lukma@denx.de
5  *
6  * Copyright (C) 2011 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
7  * Copyright (C) 2011 Richard Zhao, Linaro <richard.zhao@linaro.org>
8  * Copyright (C) 2011-2012 Mike Turquette, Linaro Ltd <mturquette@linaro.org>
9  *
10  * Simple multiplexer clock implementation
11  */
12 
13 /*
14  * U-Boot CCF porting node:
15  *
16  * The Linux kernel - as of tag: 5.0-rc3 is using also the imx_clk_fixup_mux()
17  * version of CCF mux. It is used on e.g. imx6q to provide fixes (like
18  * imx_cscmr1_fixup) for broken HW.
19  *
20  * At least for IMX6Q (but NOT IMX6QP) it is important when we set the parent
21  * clock.
22  */
23 
24 #define LOG_CATEGORY UCLASS_CLK
25 
26 #include <common.h>
27 #include <clk.h>
28 #include <clk-uclass.h>
29 #include <log.h>
30 #include <malloc.h>
31 #include <asm/io.h>
32 #include <dm/device.h>
33 #include <dm/device_compat.h>
34 #include <dm/devres.h>
35 #include <dm/uclass.h>
36 #include <linux/bitops.h>
37 #include <linux/clk-provider.h>
38 #include <linux/err.h>
39 
40 #include "clk.h"
41 
42 #define UBOOT_DM_CLK_CCF_MUX "ccf_clk_mux"
43 
clk_mux_val_to_index(struct clk * clk,u32 * table,unsigned int flags,unsigned int val)44 int clk_mux_val_to_index(struct clk *clk, u32 *table, unsigned int flags,
45 			 unsigned int val)
46 {
47 	struct clk_mux *mux = to_clk_mux(clk);
48 	int num_parents = mux->num_parents;
49 
50 	if (table) {
51 		int i;
52 
53 		for (i = 0; i < num_parents; i++)
54 			if (table[i] == val)
55 				return i;
56 		return -EINVAL;
57 	}
58 
59 	if (val && (flags & CLK_MUX_INDEX_BIT))
60 		val = ffs(val) - 1;
61 
62 	if (val && (flags & CLK_MUX_INDEX_ONE))
63 		val--;
64 
65 	if (val >= num_parents)
66 		return -EINVAL;
67 
68 	return val;
69 }
70 
clk_mux_index_to_val(u32 * table,unsigned int flags,u8 index)71 unsigned int clk_mux_index_to_val(u32 *table, unsigned int flags, u8 index)
72 {
73 	unsigned int val = index;
74 
75 	if (table) {
76 		val = table[index];
77 	} else {
78 		if (flags & CLK_MUX_INDEX_BIT)
79 			val = 1 << index;
80 
81 		if (flags & CLK_MUX_INDEX_ONE)
82 			val++;
83 	}
84 
85 	return val;
86 }
87 
clk_mux_get_parent(struct clk * clk)88 u8 clk_mux_get_parent(struct clk *clk)
89 {
90 	struct clk_mux *mux = to_clk_mux(clk);
91 	u32 val;
92 
93 #if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
94 	val = mux->io_mux_val;
95 #else
96 	val = readl(mux->reg);
97 #endif
98 	val >>= mux->shift;
99 	val &= mux->mask;
100 
101 	return clk_mux_val_to_index(clk, mux->table, mux->flags, val);
102 }
103 
clk_fetch_parent_index(struct clk * clk,struct clk * parent)104 static int clk_fetch_parent_index(struct clk *clk,
105 				  struct clk *parent)
106 {
107 	struct clk_mux *mux = to_clk_mux(clk);
108 
109 	int i;
110 
111 	if (!parent)
112 		return -EINVAL;
113 
114 	for (i = 0; i < mux->num_parents; i++) {
115 		if (!strcmp(parent->dev->name, mux->parent_names[i]))
116 			return i;
117 	}
118 
119 	return -EINVAL;
120 }
121 
clk_mux_set_parent(struct clk * clk,struct clk * parent)122 static int clk_mux_set_parent(struct clk *clk, struct clk *parent)
123 {
124 	struct clk_mux *mux = to_clk_mux(clk);
125 	int index;
126 	u32 val;
127 	u32 reg;
128 
129 	index = clk_fetch_parent_index(clk, parent);
130 	if (index < 0) {
131 		log_err("Could not fetch index\n");
132 		return index;
133 	}
134 
135 	val = clk_mux_index_to_val(mux->table, mux->flags, index);
136 
137 	if (mux->flags & CLK_MUX_HIWORD_MASK) {
138 		reg = mux->mask << (mux->shift + 16);
139 	} else {
140 #if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
141 		reg = mux->io_mux_val;
142 #else
143 		reg = readl(mux->reg);
144 #endif
145 		reg &= ~(mux->mask << mux->shift);
146 	}
147 	val = val << mux->shift;
148 	reg |= val;
149 #if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
150 	mux->io_mux_val = reg;
151 #else
152 	writel(reg, mux->reg);
153 #endif
154 
155 	return 0;
156 }
157 
158 const struct clk_ops clk_mux_ops = {
159 	.get_rate = clk_generic_get_rate,
160 	.set_parent = clk_mux_set_parent,
161 };
162 
clk_hw_register_mux_table(struct device * dev,const char * name,const char * const * parent_names,u8 num_parents,unsigned long flags,void __iomem * reg,u8 shift,u32 mask,u8 clk_mux_flags,u32 * table)163 struct clk *clk_hw_register_mux_table(struct device *dev, const char *name,
164 		const char * const *parent_names, u8 num_parents,
165 		unsigned long flags,
166 		void __iomem *reg, u8 shift, u32 mask,
167 		u8 clk_mux_flags, u32 *table)
168 {
169 	struct clk_mux *mux;
170 	struct clk *clk;
171 	u8 width = 0;
172 	int ret;
173 
174 	if (clk_mux_flags & CLK_MUX_HIWORD_MASK) {
175 		width = fls(mask) - ffs(mask) + 1;
176 		if (width + shift > 16) {
177 			dev_err(dev, "mux value exceeds LOWORD field\n");
178 			return ERR_PTR(-EINVAL);
179 		}
180 	}
181 
182 	/* allocate the mux */
183 	mux = kzalloc(sizeof(*mux), GFP_KERNEL);
184 	if (!mux)
185 		return ERR_PTR(-ENOMEM);
186 
187 	/* U-boot specific assignments */
188 	mux->parent_names = parent_names;
189 	mux->num_parents = num_parents;
190 
191 	/* struct clk_mux assignments */
192 	mux->reg = reg;
193 	mux->shift = shift;
194 	mux->mask = mask;
195 	mux->flags = clk_mux_flags;
196 	mux->table = table;
197 #if IS_ENABLED(CONFIG_SANDBOX_CLK_CCF)
198 	mux->io_mux_val = *(u32 *)reg;
199 #endif
200 
201 	clk = &mux->clk;
202 	clk->flags = flags;
203 
204 	/*
205 	 * Read the current mux setup - so we assign correct parent.
206 	 *
207 	 * Changing parent would require changing internals of udevice struct
208 	 * for the corresponding clock (to do that define .set_parent() method).
209 	 */
210 	ret = clk_register(clk, UBOOT_DM_CLK_CCF_MUX, name,
211 			   parent_names[clk_mux_get_parent(clk)]);
212 	if (ret) {
213 		kfree(mux);
214 		return ERR_PTR(ret);
215 	}
216 
217 	return clk;
218 }
219 
clk_register_mux_table(struct device * dev,const char * name,const char * const * parent_names,u8 num_parents,unsigned long flags,void __iomem * reg,u8 shift,u32 mask,u8 clk_mux_flags,u32 * table)220 struct clk *clk_register_mux_table(struct device *dev, const char *name,
221 		const char * const *parent_names, u8 num_parents,
222 		unsigned long flags,
223 		void __iomem *reg, u8 shift, u32 mask,
224 		u8 clk_mux_flags, u32 *table)
225 {
226 	struct clk *clk;
227 
228 	clk = clk_hw_register_mux_table(dev, name, parent_names, num_parents,
229 				       flags, reg, shift, mask, clk_mux_flags,
230 				       table);
231 	if (IS_ERR(clk))
232 		return ERR_CAST(clk);
233 	return clk;
234 }
235 
clk_register_mux(struct device * dev,const char * name,const char * const * parent_names,u8 num_parents,unsigned long flags,void __iomem * reg,u8 shift,u8 width,u8 clk_mux_flags)236 struct clk *clk_register_mux(struct device *dev, const char *name,
237 		const char * const *parent_names, u8 num_parents,
238 		unsigned long flags,
239 		void __iomem *reg, u8 shift, u8 width,
240 		u8 clk_mux_flags)
241 {
242 	u32 mask = BIT(width) - 1;
243 
244 	return clk_register_mux_table(dev, name, parent_names, num_parents,
245 				      flags, reg, shift, mask, clk_mux_flags,
246 				      NULL);
247 }
248 
249 U_BOOT_DRIVER(ccf_clk_mux) = {
250 	.name	= UBOOT_DM_CLK_CCF_MUX,
251 	.id	= UCLASS_CLK,
252 	.ops	= &clk_mux_ops,
253 	.flags = DM_FLAG_PRE_RELOC,
254 };
255