329f4580c5a01d0deb12837213e57c58df65acd2
[oweals/u-boot.git] / drivers / clk / imx / clk-imxrt1050.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright(C) 2019
4  * Author(s): Giulio Benetti <giulio.benetti@benettiengineering.com>
5  */
6
7 #include <common.h>
8 #include <clk.h>
9 #include <clk-uclass.h>
10 #include <dm.h>
11 #include <asm/arch/clock.h>
12 #include <asm/arch/imx-regs.h>
13 #include <dt-bindings/clock/imxrt1050-clock.h>
14
15 #include "clk.h"
16
17 static ulong imxrt1050_clk_get_rate(struct clk *clk)
18 {
19         struct clk *c;
20         int ret;
21
22         debug("%s(#%lu)\n", __func__, clk->id);
23
24         ret = clk_get_by_id(clk->id, &c);
25         if (ret)
26                 return ret;
27
28         return clk_get_rate(c);
29 }
30
31 static ulong imxrt1050_clk_set_rate(struct clk *clk, ulong rate)
32 {
33         struct clk *c;
34         int ret;
35
36         debug("%s(#%lu), rate: %lu\n", __func__, clk->id, rate);
37
38         ret = clk_get_by_id(clk->id, &c);
39         if (ret)
40                 return ret;
41
42         return clk_set_rate(c, rate);
43 }
44
45 static int __imxrt1050_clk_enable(struct clk *clk, bool enable)
46 {
47         struct clk *c;
48         int ret;
49
50         debug("%s(#%lu) en: %d\n", __func__, clk->id, enable);
51
52         ret = clk_get_by_id(clk->id, &c);
53         if (ret)
54                 return ret;
55
56         if (enable)
57                 ret = clk_enable(c);
58         else
59                 ret = clk_disable(c);
60
61         return ret;
62 }
63
64 static int imxrt1050_clk_disable(struct clk *clk)
65 {
66         return __imxrt1050_clk_enable(clk, 0);
67 }
68
69 static int imxrt1050_clk_enable(struct clk *clk)
70 {
71         return __imxrt1050_clk_enable(clk, 1);
72 }
73
74 static int imxrt1050_clk_set_parent(struct clk *clk, struct clk *parent)
75 {
76         struct clk *c, *cp;
77         int ret;
78
79         debug("%s(#%lu), parent: %lu\n", __func__, clk->id, parent->id);
80
81         ret = clk_get_by_id(clk->id, &c);
82         if (ret)
83                 return ret;
84
85         ret = clk_get_by_id(parent->id, &cp);
86         if (ret)
87                 return ret;
88
89         return clk_set_parent(c, cp);
90 }
91
92 static struct clk_ops imxrt1050_clk_ops = {
93         .set_rate = imxrt1050_clk_set_rate,
94         .get_rate = imxrt1050_clk_get_rate,
95         .enable = imxrt1050_clk_enable,
96         .disable = imxrt1050_clk_disable,
97         .set_parent = imxrt1050_clk_set_parent,
98 };
99
100 static const char * const pll_ref_sels[] = {"osc", "dummy", };
101 static const char * const pll1_bypass_sels[] = {"pll1_arm", "pll1_arm_ref_sel", };
102 static const char * const pll2_bypass_sels[] = {"pll2_sys", "pll2_sys_ref_sel", };
103 static const char * const pll3_bypass_sels[] = {"pll3_usb_otg", "pll3_usb_otg_ref_sel", };
104 static const char * const pll5_bypass_sels[] = {"pll5_video", "pll5_video_ref_sel", };
105
106 static const char *const pre_periph_sels[] = { "pll2_sys", "pll2_pfd2_396m", "pll2_pfd0_352m", "arm_podf", };
107 static const char *const periph_sels[] = { "pre_periph_sel", "todo", };
108 static const char *const usdhc_sels[] = { "pll2_pfd2_396m", "pll2_pfd0_352m", };
109 static const char *const lpuart_sels[] = { "pll3_80m", "osc", };
110 static const char *const semc_alt_sels[] = { "pll2_pfd2_396m", "pll3_pfd1_664_62m", };
111 static const char *const semc_sels[] = { "periph_sel", "semc_alt_sel", };
112 static const char *const lcdif_sels[] = { "pll2_sys", "pll3_pfd3_454_74m", "pll5_video", "pll2_pfd0_352m", "pll2_pfd1_594m", "pll3_pfd1_664_62m"};
113
114 static int imxrt1050_clk_probe(struct udevice *dev)
115 {
116         void *base;
117
118         /* Anatop clocks */
119         base = (void *)ANATOP_BASE_ADDR;
120
121         clk_dm(IMXRT1050_CLK_PLL1_REF_SEL,
122                imx_clk_mux("pll1_arm_ref_sel", base + 0x0, 14, 2,
123                            pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
124         clk_dm(IMXRT1050_CLK_PLL2_REF_SEL,
125                imx_clk_mux("pll2_sys_ref_sel", base + 0x30, 14, 2,
126                            pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
127         clk_dm(IMXRT1050_CLK_PLL3_REF_SEL,
128                imx_clk_mux("pll3_usb_otg_ref_sel", base + 0x10, 14, 2,
129                            pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
130         clk_dm(IMXRT1050_CLK_PLL5_REF_SEL,
131                imx_clk_mux("pll5_video_ref_sel", base + 0xa0, 14, 2,
132                            pll_ref_sels, ARRAY_SIZE(pll_ref_sels)));
133
134         clk_dm(IMXRT1050_CLK_PLL1_ARM,
135                imx_clk_pllv3(IMX_PLLV3_SYS, "pll1_arm", "pll1_arm_ref_sel",
136                              base + 0x0, 0x7f));
137         clk_dm(IMXRT1050_CLK_PLL2_SYS,
138                imx_clk_pllv3(IMX_PLLV3_GENERIC, "pll2_sys", "pll2_sys_ref_sel",
139                              base + 0x30, 0x1));
140         clk_dm(IMXRT1050_CLK_PLL3_USB_OTG,
141                imx_clk_pllv3(IMX_PLLV3_USB, "pll3_usb_otg",
142                              "pll3_usb_otg_ref_sel",
143                              base + 0x10, 0x1));
144         clk_dm(IMXRT1050_CLK_PLL5_VIDEO,
145                imx_clk_pllv3(IMX_PLLV3_AV, "pll5_video", "pll5_video_ref_sel",
146                              base + 0xa0, 0x7f));
147
148         /* PLL bypass out */
149         clk_dm(IMXRT1050_CLK_PLL1_BYPASS,
150                imx_clk_mux_flags("pll1_bypass", base + 0x0, 16, 1,
151                                  pll1_bypass_sels,
152                                  ARRAY_SIZE(pll1_bypass_sels),
153                                  CLK_SET_RATE_PARENT));
154         clk_dm(IMXRT1050_CLK_PLL2_BYPASS,
155                imx_clk_mux_flags("pll2_bypass", base + 0x30, 16, 1,
156                                  pll2_bypass_sels,
157                                  ARRAY_SIZE(pll2_bypass_sels),
158                                  CLK_SET_RATE_PARENT));
159         clk_dm(IMXRT1050_CLK_PLL3_BYPASS,
160                imx_clk_mux_flags("pll3_bypass", base + 0x10, 16, 1,
161                                  pll3_bypass_sels,
162                                  ARRAY_SIZE(pll3_bypass_sels),
163                                  CLK_SET_RATE_PARENT));
164         clk_dm(IMXRT1050_CLK_PLL5_BYPASS,
165                imx_clk_mux_flags("pll5_bypass", base + 0xa0, 16, 1,
166                                  pll5_bypass_sels,
167                                  ARRAY_SIZE(pll5_bypass_sels),
168                                  CLK_SET_RATE_PARENT));
169
170         clk_dm(IMXRT1050_CLK_VIDEO_POST_DIV_SEL,
171                imx_clk_divider("video_post_div_sel", "pll5_video",
172                                base + 0xa0, 19, 2));
173         clk_dm(IMXRT1050_CLK_VIDEO_DIV,
174                imx_clk_divider("video_div", "video_post_div_sel",
175                                base + 0x170, 30, 2));
176
177         clk_dm(IMXRT1050_CLK_PLL3_80M,
178                imx_clk_fixed_factor("pll3_80m",  "pll3_usb_otg",   1, 6));
179
180         clk_dm(IMXRT1050_CLK_PLL2_PFD0_352M,
181                imx_clk_pfd("pll2_pfd0_352m", "pll2_sys", base + 0x100, 0));
182         clk_dm(IMXRT1050_CLK_PLL2_PFD1_594M,
183                imx_clk_pfd("pll2_pfd1_594m", "pll2_sys", base + 0x100, 1));
184         clk_dm(IMXRT1050_CLK_PLL2_PFD2_396M,
185                imx_clk_pfd("pll2_pfd2_396m", "pll2_sys", base + 0x100, 2));
186         clk_dm(IMXRT1050_CLK_PLL3_PFD1_664_62M,
187                imx_clk_pfd("pll3_pfd1_664_62m", "pll3_usb_otg", base + 0xf0,
188                            1));
189         clk_dm(IMXRT1050_CLK_PLL3_PFD3_454_74M,
190                imx_clk_pfd("pll3_pfd3_454_74m", "pll3_usb_otg", base + 0xf0,
191                            3));
192
193         /* CCM clocks */
194         base = dev_read_addr_ptr(dev);
195         if (base == (void *)FDT_ADDR_T_NONE)
196                 return -EINVAL;
197
198         clk_dm(IMXRT1050_CLK_ARM_PODF,
199                imx_clk_divider("arm_podf", "pll1_arm",
200                                base + 0x10, 0, 3));
201
202         clk_dm(IMXRT1050_CLK_PRE_PERIPH_SEL,
203                imx_clk_mux("pre_periph_sel", base + 0x18, 18, 2,
204                            pre_periph_sels, ARRAY_SIZE(pre_periph_sels)));
205         clk_dm(IMXRT1050_CLK_PERIPH_SEL,
206                imx_clk_mux("periph_sel", base + 0x14, 25, 1,
207                            periph_sels, ARRAY_SIZE(periph_sels)));
208         clk_dm(IMXRT1050_CLK_USDHC1_SEL,
209                imx_clk_mux("usdhc1_sel", base + 0x1c, 16, 1,
210                            usdhc_sels, ARRAY_SIZE(usdhc_sels)));
211         clk_dm(IMXRT1050_CLK_USDHC2_SEL,
212                imx_clk_mux("usdhc2_sel", base + 0x1c, 17, 1,
213                            usdhc_sels, ARRAY_SIZE(usdhc_sels)));
214         clk_dm(IMXRT1050_CLK_LPUART_SEL,
215                imx_clk_mux("lpuart_sel", base + 0x24, 6, 1,
216                            lpuart_sels, ARRAY_SIZE(lpuart_sels)));
217         clk_dm(IMXRT1050_CLK_SEMC_ALT_SEL,
218                imx_clk_mux("semc_alt_sel", base + 0x14, 7, 1,
219                            semc_alt_sels, ARRAY_SIZE(semc_alt_sels)));
220         clk_dm(IMXRT1050_CLK_SEMC_SEL,
221                imx_clk_mux("semc_sel", base + 0x14, 6, 1,
222                            semc_sels, ARRAY_SIZE(semc_sels)));
223         clk_dm(IMXRT1050_CLK_LCDIF_SEL,
224                imx_clk_mux("lcdif_sel", base + 0x38, 15, 3,
225                            lcdif_sels, ARRAY_SIZE(lcdif_sels)));
226
227         clk_dm(IMXRT1050_CLK_AHB_PODF,
228                imx_clk_divider("ahb_podf", "periph_sel",
229                                base + 0x14, 10, 3));
230         clk_dm(IMXRT1050_CLK_USDHC1_PODF,
231                imx_clk_divider("usdhc1_podf", "usdhc1_sel",
232                                base + 0x24, 11, 3));
233         clk_dm(IMXRT1050_CLK_USDHC2_PODF,
234                imx_clk_divider("usdhc2_podf", "usdhc2_sel",
235                                base + 0x24, 16, 3));
236         clk_dm(IMXRT1050_CLK_LPUART_PODF,
237                imx_clk_divider("lpuart_podf", "lpuart_sel",
238                                base + 0x24, 0, 6));
239         clk_dm(IMXRT1050_CLK_SEMC_PODF,
240                imx_clk_divider("semc_podf", "semc_sel",
241                                base + 0x14, 16, 3));
242         clk_dm(IMXRT1050_CLK_LCDIF_PRED,
243                imx_clk_divider("lcdif_pred", "lcdif_sel",
244                                base + 0x38, 12, 3));
245         clk_dm(IMXRT1050_CLK_LCDIF_PODF,
246                imx_clk_divider("lcdif_podf", "lcdif_pred",
247                                base + 0x18, 23, 3));
248
249         clk_dm(IMXRT1050_CLK_USDHC1,
250                imx_clk_gate2("usdhc1", "usdhc1_podf", base + 0x80, 2));
251         clk_dm(IMXRT1050_CLK_USDHC2,
252                imx_clk_gate2("usdhc2", "usdhc2_podf", base + 0x80, 4));
253         clk_dm(IMXRT1050_CLK_LPUART1,
254                imx_clk_gate2("lpuart1", "lpuart_podf", base + 0x7c, 24));
255         clk_dm(IMXRT1050_CLK_SEMC,
256                imx_clk_gate2("semc", "semc_podf", base + 0x74, 4));
257         clk_dm(IMXRT1050_CLK_LCDIF,
258                imx_clk_gate2("lcdif", "lcdif_podf", base + 0x70, 28));
259
260         struct clk *clk, *clk1;
261
262 #ifdef CONFIG_SPL_BUILD
263         /* bypass pll1 before setting its rate */
264         clk_get_by_id(IMXRT1050_CLK_PLL1_REF_SEL, &clk);
265         clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1);
266         clk_set_parent(clk1, clk);
267
268         clk_get_by_id(IMXRT1050_CLK_PLL1_ARM, &clk);
269         clk_enable(clk);
270         clk_set_rate(clk, 1056000000UL);
271
272         clk_get_by_id(IMXRT1050_CLK_PLL1_BYPASS, &clk1);
273         clk_set_parent(clk1, clk);
274
275         clk_get_by_id(IMXRT1050_CLK_SEMC_SEL, &clk1);
276         clk_get_by_id(IMXRT1050_CLK_SEMC_ALT_SEL, &clk);
277         clk_set_parent(clk1, clk);
278
279         clk_get_by_id(IMXRT1050_CLK_PLL2_SYS, &clk);
280         clk_enable(clk);
281         clk_set_rate(clk, 528000000UL);
282
283         clk_get_by_id(IMXRT1050_CLK_PLL2_BYPASS, &clk1);
284         clk_set_parent(clk1, clk);
285
286         /* Configure PLL3_USB_OTG to 480MHz */
287         clk_get_by_id(IMXRT1050_CLK_PLL3_USB_OTG, &clk);
288         clk_enable(clk);
289         clk_set_rate(clk, 480000000UL);
290
291         clk_get_by_id(IMXRT1050_CLK_PLL3_BYPASS, &clk1);
292         clk_set_parent(clk1, clk);
293 #else
294         /* Set PLL5 for LCDIF to its default 650Mhz */
295         clk_get_by_id(IMXRT1050_CLK_PLL5_VIDEO, &clk);
296         clk_enable(clk);
297         clk_set_rate(clk, 650000000UL);
298
299         clk_get_by_id(IMXRT1050_CLK_PLL5_BYPASS, &clk1);
300         clk_set_parent(clk1, clk);
301 #endif
302
303         return 0;
304 }
305
306 static const struct udevice_id imxrt1050_clk_ids[] = {
307         { .compatible = "fsl,imxrt1050-ccm" },
308         { },
309 };
310
311 U_BOOT_DRIVER(imxrt1050_clk) = {
312         .name = "clk_imxrt1050",
313         .id = UCLASS_CLK,
314         .of_match = imxrt1050_clk_ids,
315         .ops = &imxrt1050_clk_ops,
316         .probe = imxrt1050_clk_probe,
317         .flags = DM_FLAG_PRE_RELOC,
318 };