1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3 * UTMI clock support for AT91 architectures.
4 *
5 * Copyright (C) 2020 Microchip Technology Inc. and its subsidiaries
6 *
7 * Author: Claudiu Beznea <claudiu.beznea@microchip.com>
8 *
9 * Based on drivers/clk/at91/clk-utmi.c from Linux.
10 */
11 #include <asm/processor.h>
12 #include <common.h>
13 #include <clk-uclass.h>
14 #include <dm.h>
15 #include <linux/clk-provider.h>
16 #include <linux/clk/at91_pmc.h>
17 #include <mach/at91_sfr.h>
18 #include <regmap.h>
19 #include <syscon.h>
20
21 #include "pmc.h"
22
23 #define UBOOT_DM_CLK_AT91_UTMI "at91-utmi-clk"
24 #define UBOOT_DM_CLK_AT91_SAMA7G5_UTMI "at91-sama7g5-utmi-clk"
25
26 /*
27 * The purpose of this clock is to generate a 480 MHz signal. A different
28 * rate can't be configured.
29 */
30 #define UTMI_RATE 480000000
31
32 struct clk_utmi {
33 void __iomem *base;
34 struct regmap *regmap_sfr;
35 struct clk clk;
36 };
37
38 #define to_clk_utmi(_clk) container_of(_clk, struct clk_utmi, clk)
39
clk_utmi_ready(struct regmap * regmap)40 static inline bool clk_utmi_ready(struct regmap *regmap)
41 {
42 unsigned int status;
43
44 pmc_read(regmap, AT91_PMC_SR, &status);
45
46 return !!(status & AT91_PMC_LOCKU);
47 }
48
clk_utmi_enable(struct clk * clk)49 static int clk_utmi_enable(struct clk *clk)
50 {
51 struct clk_utmi *utmi = to_clk_utmi(clk);
52 unsigned int uckr = AT91_PMC_UPLLEN | AT91_PMC_UPLLCOUNT |
53 AT91_PMC_BIASEN;
54 unsigned int utmi_ref_clk_freq;
55 ulong parent_rate = clk_get_parent_rate(clk);
56
57 /*
58 * If mainck rate is different from 12 MHz, we have to configure the
59 * FREQ field of the SFR_UTMICKTRIM register to generate properly
60 * the utmi clock.
61 */
62 switch (parent_rate) {
63 case 12000000:
64 utmi_ref_clk_freq = 0;
65 break;
66 case 16000000:
67 utmi_ref_clk_freq = 1;
68 break;
69 case 24000000:
70 utmi_ref_clk_freq = 2;
71 break;
72 /*
73 * Not supported on SAMA5D2 but it's not an issue since MAINCK
74 * maximum value is 24 MHz.
75 */
76 case 48000000:
77 utmi_ref_clk_freq = 3;
78 break;
79 default:
80 debug("UTMICK: unsupported mainck rate\n");
81 return -EINVAL;
82 }
83
84 if (utmi->regmap_sfr) {
85 regmap_update_bits(utmi->regmap_sfr, AT91_SFR_UTMICKTRIM,
86 AT91_UTMICKTRIM_FREQ, utmi_ref_clk_freq);
87 } else if (utmi_ref_clk_freq) {
88 debug("UTMICK: sfr node required\n");
89 return -EINVAL;
90 }
91
92 pmc_update_bits(utmi->base, AT91_CKGR_UCKR, uckr, uckr);
93
94 while (!clk_utmi_ready(utmi->base)) {
95 debug("waiting for utmi...\n");
96 cpu_relax();
97 }
98
99 return 0;
100 }
101
clk_utmi_disable(struct clk * clk)102 static int clk_utmi_disable(struct clk *clk)
103 {
104 struct clk_utmi *utmi = to_clk_utmi(clk);
105
106 pmc_update_bits(utmi->base, AT91_CKGR_UCKR, AT91_PMC_UPLLEN, 0);
107
108 return 0;
109 }
110
clk_utmi_get_rate(struct clk * clk)111 static ulong clk_utmi_get_rate(struct clk *clk)
112 {
113 /* UTMI clk rate is fixed. */
114 return UTMI_RATE;
115 }
116
117 static const struct clk_ops utmi_ops = {
118 .enable = clk_utmi_enable,
119 .disable = clk_utmi_disable,
120 .get_rate = clk_utmi_get_rate,
121 };
122
at91_clk_register_utmi(void __iomem * base,struct udevice * dev,const char * name,const char * parent_name)123 struct clk *at91_clk_register_utmi(void __iomem *base, struct udevice *dev,
124 const char *name, const char *parent_name)
125 {
126 struct udevice *syscon;
127 struct clk_utmi *utmi;
128 struct clk *clk;
129 int ret;
130
131 if (!base || !dev || !name || !parent_name)
132 return ERR_PTR(-EINVAL);
133
134 ret = uclass_get_device_by_phandle(UCLASS_SYSCON, dev,
135 "regmap-sfr", &syscon);
136 if (ret)
137 return ERR_PTR(ret);
138
139 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
140 if (!utmi)
141 return ERR_PTR(-ENOMEM);
142
143 utmi->base = base;
144 utmi->regmap_sfr = syscon_get_regmap(syscon);
145 if (!utmi->regmap_sfr) {
146 kfree(utmi);
147 return ERR_PTR(-ENODEV);
148 }
149
150 clk = &utmi->clk;
151 clk->flags = CLK_GET_RATE_NOCACHE;
152 ret = clk_register(clk, UBOOT_DM_CLK_AT91_UTMI, name, parent_name);
153 if (ret) {
154 kfree(utmi);
155 clk = ERR_PTR(ret);
156 }
157
158 return clk;
159 }
160
161 U_BOOT_DRIVER(at91_utmi_clk) = {
162 .name = UBOOT_DM_CLK_AT91_UTMI,
163 .id = UCLASS_CLK,
164 .ops = &utmi_ops,
165 .flags = DM_FLAG_PRE_RELOC,
166 };
167
clk_utmi_sama7g5_enable(struct clk * clk)168 static int clk_utmi_sama7g5_enable(struct clk *clk)
169 {
170 struct clk_utmi *utmi = to_clk_utmi(clk);
171 ulong parent_rate = clk_get_parent_rate(clk);
172 unsigned int val;
173
174 switch (parent_rate) {
175 case 16000000:
176 val = 0;
177 break;
178 case 20000000:
179 val = 2;
180 break;
181 case 24000000:
182 val = 3;
183 break;
184 case 32000000:
185 val = 5;
186 break;
187 default:
188 debug("UTMICK: unsupported main_xtal rate\n");
189 return -EINVAL;
190 }
191
192 pmc_write(utmi->base, AT91_PMC_XTALF, val);
193
194 return 0;
195 }
196
197 static const struct clk_ops sama7g5_utmi_ops = {
198 .enable = clk_utmi_sama7g5_enable,
199 .get_rate = clk_utmi_get_rate,
200 };
201
at91_clk_sama7g5_register_utmi(void __iomem * base,const char * name,const char * parent_name)202 struct clk *at91_clk_sama7g5_register_utmi(void __iomem *base,
203 const char *name, const char *parent_name)
204 {
205 struct clk_utmi *utmi;
206 struct clk *clk;
207 int ret;
208
209 if (!base || !name || !parent_name)
210 return ERR_PTR(-EINVAL);
211
212 utmi = kzalloc(sizeof(*utmi), GFP_KERNEL);
213 if (!utmi)
214 return ERR_PTR(-ENOMEM);
215
216 utmi->base = base;
217
218 clk = &utmi->clk;
219 ret = clk_register(clk, UBOOT_DM_CLK_AT91_SAMA7G5_UTMI, name,
220 parent_name);
221 if (ret) {
222 kfree(utmi);
223 clk = ERR_PTR(ret);
224 }
225
226 return clk;
227 }
228
229 U_BOOT_DRIVER(at91_sama7g5_utmi_clk) = {
230 .name = UBOOT_DM_CLK_AT91_SAMA7G5_UTMI,
231 .id = UCLASS_CLK,
232 .ops = &sama7g5_utmi_ops,
233 .flags = DM_FLAG_PRE_RELOC,
234 };
235