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