1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (c) 2018 BayLibre, SAS
4  * Author: Neil Armstrong <narmstrong@baylibre.com>
5  */
6 
7 #include <linux/of_address.h>
8 #include <linux/platform_device.h>
9 #include <linux/bitfield.h>
10 #include <linux/seq_file.h>
11 #include <linux/debugfs.h>
12 #include <linux/regmap.h>
13 
14 #define MSR_CLK_DUTY		0x0
15 #define MSR_CLK_REG0		0x4
16 #define MSR_CLK_REG1		0x8
17 #define MSR_CLK_REG2		0xc
18 
19 #define MSR_DURATION		GENMASK(15, 0)
20 #define MSR_ENABLE		BIT(16)
21 #define MSR_CONT		BIT(17) /* continuous measurement */
22 #define MSR_INTR		BIT(18) /* interrupts */
23 #define MSR_RUN			BIT(19)
24 #define MSR_CLK_SRC		GENMASK(26, 20)
25 #define MSR_BUSY		BIT(31)
26 
27 #define MSR_VAL_MASK		GENMASK(15, 0)
28 
29 #define DIV_MIN			32
30 #define DIV_STEP		32
31 #define DIV_MAX			640
32 
33 #define CLK_MSR_MAX		128
34 
35 struct meson_msr_id {
36 	struct meson_msr *priv;
37 	unsigned int id;
38 	const char *name;
39 };
40 
41 struct meson_msr {
42 	struct regmap *regmap;
43 	struct meson_msr_id msr_table[CLK_MSR_MAX];
44 };
45 
46 #define CLK_MSR_ID(__id, __name) \
47 	[__id] = {.id = __id, .name = __name,}
48 
49 static struct meson_msr_id clk_msr_m8[CLK_MSR_MAX] = {
50 	CLK_MSR_ID(0, "ring_osc_out_ee0"),
51 	CLK_MSR_ID(1, "ring_osc_out_ee1"),
52 	CLK_MSR_ID(2, "ring_osc_out_ee2"),
53 	CLK_MSR_ID(3, "a9_ring_osck"),
54 	CLK_MSR_ID(6, "vid_pll"),
55 	CLK_MSR_ID(7, "clk81"),
56 	CLK_MSR_ID(8, "encp"),
57 	CLK_MSR_ID(9, "encl"),
58 	CLK_MSR_ID(11, "eth_rmii"),
59 	CLK_MSR_ID(13, "amclk"),
60 	CLK_MSR_ID(14, "fec_clk_0"),
61 	CLK_MSR_ID(15, "fec_clk_1"),
62 	CLK_MSR_ID(16, "fec_clk_2"),
63 	CLK_MSR_ID(18, "a9_clk_div16"),
64 	CLK_MSR_ID(19, "hdmi_sys"),
65 	CLK_MSR_ID(20, "rtc_osc_clk_out"),
66 	CLK_MSR_ID(21, "i2s_clk_in_src0"),
67 	CLK_MSR_ID(22, "clk_rmii_from_pad"),
68 	CLK_MSR_ID(23, "hdmi_ch0_tmds"),
69 	CLK_MSR_ID(24, "lvds_fifo"),
70 	CLK_MSR_ID(26, "sc_clk_int"),
71 	CLK_MSR_ID(28, "sar_adc"),
72 	CLK_MSR_ID(30, "mpll_clk_test_out"),
73 	CLK_MSR_ID(31, "audac_clkpi"),
74 	CLK_MSR_ID(32, "vdac"),
75 	CLK_MSR_ID(33, "sdhc_rx"),
76 	CLK_MSR_ID(34, "sdhc_sd"),
77 	CLK_MSR_ID(35, "mali"),
78 	CLK_MSR_ID(36, "hdmi_tx_pixel"),
79 	CLK_MSR_ID(38, "vdin_meas"),
80 	CLK_MSR_ID(39, "pcm_sclk"),
81 	CLK_MSR_ID(40, "pcm_mclk"),
82 	CLK_MSR_ID(41, "eth_rx_tx"),
83 	CLK_MSR_ID(42, "pwm_d"),
84 	CLK_MSR_ID(43, "pwm_c"),
85 	CLK_MSR_ID(44, "pwm_b"),
86 	CLK_MSR_ID(45, "pwm_a"),
87 	CLK_MSR_ID(46, "pcm2_sclk"),
88 	CLK_MSR_ID(47, "ddr_dpll_pt"),
89 	CLK_MSR_ID(48, "pwm_f"),
90 	CLK_MSR_ID(49, "pwm_e"),
91 	CLK_MSR_ID(59, "hcodec"),
92 	CLK_MSR_ID(60, "usb_32k_alt"),
93 	CLK_MSR_ID(61, "gpio"),
94 	CLK_MSR_ID(62, "vid2_pll"),
95 	CLK_MSR_ID(63, "mipi_csi_cfg"),
96 };
97 
98 static struct meson_msr_id clk_msr_gx[CLK_MSR_MAX] = {
99 	CLK_MSR_ID(0, "ring_osc_out_ee_0"),
100 	CLK_MSR_ID(1, "ring_osc_out_ee_1"),
101 	CLK_MSR_ID(2, "ring_osc_out_ee_2"),
102 	CLK_MSR_ID(3, "a53_ring_osc"),
103 	CLK_MSR_ID(4, "gp0_pll"),
104 	CLK_MSR_ID(6, "enci"),
105 	CLK_MSR_ID(7, "clk81"),
106 	CLK_MSR_ID(8, "encp"),
107 	CLK_MSR_ID(9, "encl"),
108 	CLK_MSR_ID(10, "vdac"),
109 	CLK_MSR_ID(11, "rgmii_tx"),
110 	CLK_MSR_ID(12, "pdm"),
111 	CLK_MSR_ID(13, "amclk"),
112 	CLK_MSR_ID(14, "fec_0"),
113 	CLK_MSR_ID(15, "fec_1"),
114 	CLK_MSR_ID(16, "fec_2"),
115 	CLK_MSR_ID(17, "sys_pll_div16"),
116 	CLK_MSR_ID(18, "sys_cpu_div16"),
117 	CLK_MSR_ID(19, "hdmitx_sys"),
118 	CLK_MSR_ID(20, "rtc_osc_out"),
119 	CLK_MSR_ID(21, "i2s_in_src0"),
120 	CLK_MSR_ID(22, "eth_phy_ref"),
121 	CLK_MSR_ID(23, "hdmi_todig"),
122 	CLK_MSR_ID(26, "sc_int"),
123 	CLK_MSR_ID(28, "sar_adc"),
124 	CLK_MSR_ID(31, "mpll_test_out"),
125 	CLK_MSR_ID(32, "vdec"),
126 	CLK_MSR_ID(35, "mali"),
127 	CLK_MSR_ID(36, "hdmi_tx_pixel"),
128 	CLK_MSR_ID(37, "i958"),
129 	CLK_MSR_ID(38, "vdin_meas"),
130 	CLK_MSR_ID(39, "pcm_sclk"),
131 	CLK_MSR_ID(40, "pcm_mclk"),
132 	CLK_MSR_ID(41, "eth_rx_or_rmii"),
133 	CLK_MSR_ID(42, "mp0_out"),
134 	CLK_MSR_ID(43, "fclk_div5"),
135 	CLK_MSR_ID(44, "pwm_b"),
136 	CLK_MSR_ID(45, "pwm_a"),
137 	CLK_MSR_ID(46, "vpu"),
138 	CLK_MSR_ID(47, "ddr_dpll_pt"),
139 	CLK_MSR_ID(48, "mp1_out"),
140 	CLK_MSR_ID(49, "mp2_out"),
141 	CLK_MSR_ID(50, "mp3_out"),
142 	CLK_MSR_ID(51, "nand_core"),
143 	CLK_MSR_ID(52, "sd_emmc_b"),
144 	CLK_MSR_ID(53, "sd_emmc_a"),
145 	CLK_MSR_ID(55, "vid_pll_div_out"),
146 	CLK_MSR_ID(56, "cci"),
147 	CLK_MSR_ID(57, "wave420l_c"),
148 	CLK_MSR_ID(58, "wave420l_b"),
149 	CLK_MSR_ID(59, "hcodec"),
150 	CLK_MSR_ID(60, "alt_32k"),
151 	CLK_MSR_ID(61, "gpio_msr"),
152 	CLK_MSR_ID(62, "hevc"),
153 	CLK_MSR_ID(66, "vid_lock"),
154 	CLK_MSR_ID(70, "pwm_f"),
155 	CLK_MSR_ID(71, "pwm_e"),
156 	CLK_MSR_ID(72, "pwm_d"),
157 	CLK_MSR_ID(73, "pwm_c"),
158 	CLK_MSR_ID(75, "aoclkx2_int"),
159 	CLK_MSR_ID(76, "aoclk_int"),
160 	CLK_MSR_ID(77, "rng_ring_osc_0"),
161 	CLK_MSR_ID(78, "rng_ring_osc_1"),
162 	CLK_MSR_ID(79, "rng_ring_osc_2"),
163 	CLK_MSR_ID(80, "rng_ring_osc_3"),
164 	CLK_MSR_ID(81, "vapb"),
165 	CLK_MSR_ID(82, "ge2d"),
166 };
167 
168 static int meson_measure_id(struct meson_msr_id *clk_msr_id,
169 			       unsigned int duration)
170 {
171 	struct meson_msr *priv = clk_msr_id->priv;
172 	unsigned int val;
173 	int ret;
174 
175 	regmap_write(priv->regmap, MSR_CLK_REG0, 0);
176 
177 	/* Set measurement duration */
178 	regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_DURATION,
179 			   FIELD_PREP(MSR_DURATION, duration - 1));
180 
181 	/* Set ID */
182 	regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_CLK_SRC,
183 			   FIELD_PREP(MSR_CLK_SRC, clk_msr_id->id));
184 
185 	/* Enable & Start */
186 	regmap_update_bits(priv->regmap, MSR_CLK_REG0,
187 			   MSR_RUN | MSR_ENABLE,
188 			   MSR_RUN | MSR_ENABLE);
189 
190 	ret = regmap_read_poll_timeout(priv->regmap, MSR_CLK_REG0,
191 				       val, !(val & MSR_BUSY), 10, 10000);
192 	if (ret)
193 		return ret;
194 
195 	/* Disable */
196 	regmap_update_bits(priv->regmap, MSR_CLK_REG0, MSR_ENABLE, 0);
197 
198 	/* Get the value in multiple of gate time counts */
199 	regmap_read(priv->regmap, MSR_CLK_REG2, &val);
200 
201 	if (val >= MSR_VAL_MASK)
202 		return -EINVAL;
203 
204 	return DIV_ROUND_CLOSEST_ULL((val & MSR_VAL_MASK) * 1000000ULL,
205 				     duration);
206 }
207 
208 static int meson_measure_best_id(struct meson_msr_id *clk_msr_id,
209 				    unsigned int *precision)
210 {
211 	unsigned int duration = DIV_MAX;
212 	int ret;
213 
214 	/* Start from max duration and down to min duration */
215 	do {
216 		ret = meson_measure_id(clk_msr_id, duration);
217 		if (ret >= 0)
218 			*precision = (2 * 1000000) / duration;
219 		else
220 			duration -= DIV_STEP;
221 	} while (duration >= DIV_MIN && ret == -EINVAL);
222 
223 	return ret;
224 }
225 
226 static int clk_msr_show(struct seq_file *s, void *data)
227 {
228 	struct meson_msr_id *clk_msr_id = s->private;
229 	unsigned int precision = 0;
230 	int val;
231 
232 	val = meson_measure_best_id(clk_msr_id, &precision);
233 	if (val < 0)
234 		return val;
235 
236 	seq_printf(s, "%d\t+/-%dHz\n", val, precision);
237 
238 	return 0;
239 }
240 DEFINE_SHOW_ATTRIBUTE(clk_msr);
241 
242 static int clk_msr_summary_show(struct seq_file *s, void *data)
243 {
244 	struct meson_msr_id *msr_table = s->private;
245 	unsigned int precision = 0;
246 	int val, i;
247 
248 	seq_puts(s, "  clock                     rate    precision\n");
249 	seq_puts(s, "---------------------------------------------\n");
250 
251 	for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
252 		if (!msr_table[i].name)
253 			continue;
254 
255 		val = meson_measure_best_id(&msr_table[i], &precision);
256 		if (val < 0)
257 			return val;
258 
259 		seq_printf(s, " %-20s %10d    +/-%dHz\n",
260 			   msr_table[i].name, val, precision);
261 	}
262 
263 	return 0;
264 }
265 DEFINE_SHOW_ATTRIBUTE(clk_msr_summary);
266 
267 static const struct regmap_config meson_clk_msr_regmap_config = {
268 	.reg_bits = 32,
269 	.val_bits = 32,
270 	.reg_stride = 4,
271 	.max_register = MSR_CLK_REG2,
272 };
273 
274 static int meson_msr_probe(struct platform_device *pdev)
275 {
276 	const struct meson_msr_id *match_data;
277 	struct meson_msr *priv;
278 	struct resource *res;
279 	struct dentry *root, *clks;
280 	void __iomem *base;
281 	int i;
282 
283 	priv = devm_kzalloc(&pdev->dev, sizeof(struct meson_msr),
284 			    GFP_KERNEL);
285 	if (!priv)
286 		return -ENOMEM;
287 
288 	match_data = device_get_match_data(&pdev->dev);
289 	if (!match_data) {
290 		dev_err(&pdev->dev, "failed to get match data\n");
291 		return -ENODEV;
292 	}
293 
294 	memcpy(priv->msr_table, match_data, sizeof(priv->msr_table));
295 
296 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
297 	base = devm_ioremap_resource(&pdev->dev, res);
298 	if (IS_ERR(base)) {
299 		dev_err(&pdev->dev, "io resource mapping failed\n");
300 		return PTR_ERR(base);
301 	}
302 
303 	priv->regmap = devm_regmap_init_mmio(&pdev->dev, base,
304 					     &meson_clk_msr_regmap_config);
305 	if (IS_ERR(priv->regmap))
306 		return PTR_ERR(priv->regmap);
307 
308 	root = debugfs_create_dir("meson-clk-msr", NULL);
309 	clks = debugfs_create_dir("clks", root);
310 
311 	debugfs_create_file("measure_summary", 0444, root,
312 			    priv->msr_table, &clk_msr_summary_fops);
313 
314 	for (i = 0 ; i < CLK_MSR_MAX ; ++i) {
315 		if (!priv->msr_table[i].name)
316 			continue;
317 
318 		priv->msr_table[i].priv = priv;
319 
320 		debugfs_create_file(priv->msr_table[i].name, 0444, clks,
321 				    &priv->msr_table[i], &clk_msr_fops);
322 	}
323 
324 	return 0;
325 }
326 
327 static const struct of_device_id meson_msr_match_table[] = {
328 	{
329 		.compatible = "amlogic,meson-gx-clk-measure",
330 		.data = (void *)clk_msr_gx,
331 	},
332 	{
333 		.compatible = "amlogic,meson8-clk-measure",
334 		.data = (void *)clk_msr_m8,
335 	},
336 	{
337 		.compatible = "amlogic,meson8b-clk-measure",
338 		.data = (void *)clk_msr_m8,
339 	},
340 	{ /* sentinel */ }
341 };
342 
343 static struct platform_driver meson_msr_driver = {
344 	.probe	= meson_msr_probe,
345 	.driver = {
346 		.name		= "meson_msr",
347 		.of_match_table	= meson_msr_match_table,
348 	},
349 };
350 builtin_platform_driver(meson_msr_driver);
351