1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Xilinx 'Clocking Wizard' driver
4  *
5  * Copyright (c) 2021 Macronix Inc.
6  *
7  * Author: Zhengxun Li <zhengxunli@mxic.com.tw>
8  */
9 
10 #include <clk-uclass.h>
11 #include <dm.h>
12 #include <div64.h>
13 #include <dm/device_compat.h>
14 #include <linux/iopoll.h>
15 
16 #include <linux/bitfield.h>
17 
18 #define SRR			0x0
19 
20 #define SR			0x4
21 #define SR_LOCKED		BIT(0)
22 
23 #define CCR(x)			(0x200 + ((x) * 4))
24 
25 #define FBOUT_CFG		CCR(0)
26 #define FBOUT_DIV(x)		(x)
27 #define FBOUT_DIV_MASK		GENMASK(7, 0)
28 #define FBOUT_GET_DIV(x)	FIELD_GET(FBOUT_DIV_MASK, x)
29 #define FBOUT_MUL(x)		((x) << 8)
30 #define FBOUT_MUL_MASK		GENMASK(15, 8)
31 #define FBOUT_GET_MUL(x)	FIELD_GET(FBOUT_MUL_MASK, x)
32 #define FBOUT_FRAC(x)		((x) << 16)
33 #define FBOUT_FRAC_MASK		GENMASK(25, 16)
34 #define FBOUT_GET_FRAC(x)	FIELD_GET(FBOUT_FRAC_MASK, x)
35 #define FBOUT_FRAC_EN		BIT(26)
36 
37 #define FBOUT_PHASE		CCR(1)
38 
39 #define OUT_CFG(x)		CCR(2 + ((x) * 3))
40 #define OUT_DIV(x)		(x)
41 #define OUT_DIV_MASK		GENMASK(7, 0)
42 #define OUT_GET_DIV(x)		FIELD_GET(OUT_DIV_MASK, x)
43 #define OUT_FRAC(x)		((x) << 8)
44 #define OUT_GET_MASK		GENMASK(17, 8)
45 #define OUT_GET_FRAC(x)		FIELD_GET(OUT_GET_MASK, x)
46 #define OUT_FRAC_EN		BIT(18)
47 
48 #define OUT_PHASE(x)		CCR(3 + ((x) * 3))
49 #define OUT_DUTY(x)		CCR(4 + ((x) * 3))
50 
51 #define CTRL			CCR(23)
52 #define CTRL_SEN		BIT(2)
53 #define CTRL_SADDR		BIT(1)
54 #define CTRL_LOAD		BIT(0)
55 
56 /**
57  * struct clkwzrd - Clock wizard private data structure
58  *
59  * @base:		memory base
60  * @vco_clk:		voltage-controlled oscillator frequency
61  *
62  */
63 struct clkwzd {
64 	void *base;
65 	u64 vco_clk;
66 };
67 
68 struct clkwzd_plat {
69 	fdt_addr_t addr;
70 };
71 
clk_wzrd_enable(struct clk * clk)72 static int clk_wzrd_enable(struct clk *clk)
73 {
74 	struct clkwzd *priv = dev_get_priv(clk->dev);
75 	int ret;
76 	u32 val;
77 
78 	ret = readl_poll_sleep_timeout(priv->base + SR, val, val & SR_LOCKED,
79 				       1, 100);
80 	if (!ret) {
81 		writel(CTRL_SEN | CTRL_SADDR | CTRL_LOAD, priv->base + CTRL);
82 		writel(CTRL_SADDR, priv->base + CTRL);
83 		ret = readl_poll_sleep_timeout(priv->base + SR, val,
84 					       val & SR_LOCKED, 1, 100);
85 	}
86 
87 	return ret;
88 }
89 
clk_wzrd_set_rate(struct clk * clk,ulong rate)90 static unsigned long clk_wzrd_set_rate(struct clk *clk, ulong rate)
91 {
92 	struct clkwzd *priv = dev_get_priv(clk->dev);
93 	u64 div;
94 	u32 cfg;
95 
96 	/* Get output clock divide value */
97 	div = DIV_ROUND_DOWN_ULL(priv->vco_clk * 1000, rate);
98 	if (div < 1000 || div > 255999)
99 		return -EINVAL;
100 
101 	cfg = OUT_DIV((u32)div / 1000);
102 
103 	writel(cfg, priv->base + OUT_CFG(clk->id));
104 
105 	return 0;
106 }
107 
108 static struct clk_ops clk_wzrd_ops = {
109 	.enable = clk_wzrd_enable,
110 	.set_rate = clk_wzrd_set_rate,
111 };
112 
clk_wzrd_probe(struct udevice * dev)113 static int clk_wzrd_probe(struct udevice *dev)
114 {
115 	struct clkwzd_plat *plat = dev_get_plat(dev);
116 	struct clkwzd *priv = dev_get_priv(dev);
117 	struct clk clk_in1;
118 	u64 clock, vco_clk;
119 	u32 cfg;
120 	int ret;
121 
122 	priv->base = (void *)plat->addr;
123 
124 	ret = clk_get_by_name(dev, "clk_in1", &clk_in1);
125 	if (ret < 0) {
126 		dev_err(dev, "failed to get clock\n");
127 		return ret;
128 	}
129 
130 	clock = clk_get_rate(&clk_in1);
131 	if (IS_ERR_VALUE(clock)) {
132 		dev_err(dev, "failed to get rate\n");
133 		return clock;
134 	}
135 
136 	ret = clk_enable(&clk_in1);
137 	if (ret) {
138 		dev_err(dev, "failed to enable clock\n");
139 		return ret;
140 	}
141 
142 	/* Read clock configuration registers */
143 	cfg = readl(priv->base + FBOUT_CFG);
144 
145 	/* Recalculate VCO rate */
146 	if (cfg & FBOUT_FRAC_EN)
147 		vco_clk = DIV_ROUND_DOWN_ULL(clock *
148 					     ((FBOUT_GET_MUL(cfg) * 1000) +
149 					      FBOUT_GET_FRAC(cfg)),
150 					     1000);
151 	else
152 		vco_clk = clock * FBOUT_GET_MUL(cfg);
153 
154 	priv->vco_clk = DIV_ROUND_DOWN_ULL(vco_clk, FBOUT_GET_DIV(cfg));
155 
156 	return 0;
157 }
158 
clk_wzrd_of_to_plat(struct udevice * dev)159 static int clk_wzrd_of_to_plat(struct udevice *dev)
160 {
161 	struct clkwzd_plat *plat = dev_get_plat(dev);
162 
163 	plat->addr = dev_read_addr(dev);
164 	if (plat->addr == FDT_ADDR_T_NONE)
165 		return -EINVAL;
166 
167 	return 0;
168 }
169 
170 static const struct udevice_id clk_wzrd_ids[] = {
171 	{ .compatible = "xlnx,clocking-wizard" },
172 	{ /* sentinel */ }
173 };
174 
175 U_BOOT_DRIVER(clk_wzrd) = {
176 	.name = "zynq-clk-wizard",
177 	.id = UCLASS_CLK,
178 	.of_match = clk_wzrd_ids,
179 	.ops = &clk_wzrd_ops,
180 	.probe = clk_wzrd_probe,
181 	.of_to_plat = clk_wzrd_of_to_plat,
182 	.priv_auto = sizeof(struct clkwzd),
183 	.plat_auto = sizeof(struct clkwzd_plat),
184 };
185