blob: 85074f1b86e8720b6d6778fda4a67ca441d46266 [file] [log] [blame]
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +03001/*
2 * Synopsys HSDK SDP CGU clock driver
3 *
4 * Copyright (C) 2017 Synopsys
5 * Author: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
6 *
7 * This file is licensed under the terms of the GNU General Public
8 * License version 2. This program is licensed "as is" without any
9 * warranty of any kind, whether express or implied.
10 */
11
Tom Riniabb9a042024-05-18 20:20:43 -060012#include <common.h>
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030013#include <clk-uclass.h>
14#include <div64.h>
15#include <dm.h>
Simon Glass0f2af882020-05-10 11:40:05 -060016#include <log.h>
Simon Glass4dcacfc2020-05-10 11:40:13 -060017#include <linux/bitops.h>
Simon Glassc06c1be2020-05-10 11:40:08 -060018#include <linux/bug.h>
Simon Glassdbd79542020-05-10 11:40:11 -060019#include <linux/delay.h>
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030020#include <linux/io.h>
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +030021#include <asm/arcregs.h>
Simon Glassbdd5f812023-09-14 18:21:46 -060022#include <linux/printk.h>
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030023
Eugeniy Paltsev7aa8c092020-05-07 20:31:01 +030024#include <dt-bindings/clock/snps,hsdk-cgu.h>
25
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030026/*
27 * Synopsys ARC HSDK clock tree.
28 *
29 * ------------------
30 * | 33.33 MHz xtal |
31 * ------------------
32 * |
33 * | -----------
34 * |-->| ARC PLL |
35 * | -----------
36 * | |
37 * | |-->|CGU_ARC_IDIV|----------->
38 * | |-->|CREG_CORE_IF_DIV|------->
39 * |
40 * | --------------
41 * |-->| SYSTEM PLL |
42 * | --------------
43 * | |
44 * | |-->|CGU_SYS_IDIV_APB|------->
45 * | |-->|CGU_SYS_IDIV_AXI|------->
46 * | |-->|CGU_SYS_IDIV_*|--------->
47 * | |-->|CGU_SYS_IDIV_EBI_REF|--->
48 * |
49 * | --------------
50 * |-->| TUNNEL PLL |
51 * | --------------
52 * | |
Eugeniy Paltsev74514242018-01-16 20:44:25 +030053 * | |-->|CGU_TUN_IDIV_TUN|----------->
54 * | |-->|CGU_TUN_IDIV_ROM|----------->
55 * | |-->|CGU_TUN_IDIV_PWM|----------->
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030056 * |
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030057 * | -----------
58 * |-->| DDR PLL |
59 * -----------
60 * |
61 * |---------------------------->
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +030062 *
63 * ------------------
64 * | 27.00 MHz xtal |
65 * ------------------
66 * |
67 * | ------------
68 * |-->| HDMI PLL |
69 * ------------
70 * |
71 * |-->|CGU_HDMI_IDIV_APB|------>
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030072 */
73
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030074#define CGU_ARC_IDIV 0x080
Eugeniy Paltsev74514242018-01-16 20:44:25 +030075#define CGU_TUN_IDIV_TUN 0x380
76#define CGU_TUN_IDIV_ROM 0x390
77#define CGU_TUN_IDIV_PWM 0x3A0
Eugeniy Paltsev65757132020-04-23 14:50:50 +030078#define CGU_TUN_IDIV_TIMER 0x3B0
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +030079#define CGU_HDMI_IDIV_APB 0x480
80#define CGU_SYS_IDIV_APB 0x180
81#define CGU_SYS_IDIV_AXI 0x190
82#define CGU_SYS_IDIV_ETH 0x1A0
83#define CGU_SYS_IDIV_USB 0x1B0
84#define CGU_SYS_IDIV_SDIO 0x1C0
85#define CGU_SYS_IDIV_HDMI 0x1D0
86#define CGU_SYS_IDIV_GFX_CORE 0x1E0
87#define CGU_SYS_IDIV_GFX_DMA 0x1F0
88#define CGU_SYS_IDIV_GFX_CFG 0x200
89#define CGU_SYS_IDIV_DMAC_CORE 0x210
90#define CGU_SYS_IDIV_DMAC_CFG 0x220
91#define CGU_SYS_IDIV_SDIO_REF 0x230
92#define CGU_SYS_IDIV_SPI_REF 0x240
93#define CGU_SYS_IDIV_I2C_REF 0x250
94#define CGU_SYS_IDIV_UART_REF 0x260
95#define CGU_SYS_IDIV_EBI_REF 0x270
96
97#define CGU_IDIV_MASK 0xFF /* All idiv have 8 significant bits */
98
99#define CGU_ARC_PLL 0x0
100#define CGU_SYS_PLL 0x10
101#define CGU_DDR_PLL 0x20
102#define CGU_TUN_PLL 0x30
103#define CGU_HDMI_PLL 0x40
104
105#define CGU_PLL_CTRL 0x000 /* ARC PLL control register */
106#define CGU_PLL_STATUS 0x004 /* ARC PLL status register */
107#define CGU_PLL_FMEAS 0x008 /* ARC PLL frequency measurement register */
108#define CGU_PLL_MON 0x00C /* ARC PLL monitor register */
109
110#define CGU_PLL_CTRL_ODIV_SHIFT 2
111#define CGU_PLL_CTRL_IDIV_SHIFT 4
112#define CGU_PLL_CTRL_FBDIV_SHIFT 9
113#define CGU_PLL_CTRL_BAND_SHIFT 20
114
115#define CGU_PLL_CTRL_ODIV_MASK GENMASK(3, CGU_PLL_CTRL_ODIV_SHIFT)
116#define CGU_PLL_CTRL_IDIV_MASK GENMASK(8, CGU_PLL_CTRL_IDIV_SHIFT)
117#define CGU_PLL_CTRL_FBDIV_MASK GENMASK(15, CGU_PLL_CTRL_FBDIV_SHIFT)
118
119#define CGU_PLL_CTRL_PD BIT(0)
120#define CGU_PLL_CTRL_BYPASS BIT(1)
121
122#define CGU_PLL_STATUS_LOCK BIT(0)
123#define CGU_PLL_STATUS_ERR BIT(1)
124
125#define HSDK_PLL_MAX_LOCK_TIME 100 /* 100 us */
126
127#define CREG_CORE_IF_DIV 0x000 /* ARC CORE interface divider */
128#define CORE_IF_CLK_THRESHOLD_HZ 500000000
129#define CREG_CORE_IF_CLK_DIV_1 0x0
130#define CREG_CORE_IF_CLK_DIV_2 0x1
131
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300132#define MIN_PLL_RATE 100000000 /* 100 MHz */
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300133#define PARENT_RATE_33 33333333 /* fixed clock - xtal */
134#define PARENT_RATE_27 27000000 /* fixed clock - xtal */
Eugeniy Paltsev65757132020-04-23 14:50:50 +0300135#define CGU_MAX_CLOCKS 27
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300136
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300137#define MAX_FREQ_VARIATIONS 6
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300138
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300139struct hsdk_idiv_cfg {
Eugeniy Paltsev0b8ac7c2020-05-07 17:52:11 +0300140 const u32 oft;
141 const u8 val[MAX_FREQ_VARIATIONS];
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300142};
143
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300144struct hsdk_div_full_cfg {
145 const u32 clk_rate[MAX_FREQ_VARIATIONS];
146 const u32 pll_rate[MAX_FREQ_VARIATIONS];
147 const struct hsdk_idiv_cfg idiv[];
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300148};
149
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300150static const struct hsdk_div_full_cfg hsdk_4xd_tun_clk_cfg = {
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300151 { 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 },
Eugeniy Paltsevc6f15de2020-04-16 22:35:11 +0300152 { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300153 { CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } },
154 { CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } },
Eugeniy Paltsev65757132020-04-23 14:50:50 +0300155 { CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } },
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300156 { CGU_TUN_IDIV_TIMER, { 12, 12, 12, 12, 15, 12 } },
157 { /* last one */ }
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300158 }
159};
160
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300161static const struct hsdk_div_full_cfg hsdk_tun_clk_cfg = {
162 { 25000000, 50000000, 75000000, 100000000, 125000000, 150000000 },
163 { 600000000, 600000000, 600000000, 600000000, 750000000, 600000000 }, {
164 { CGU_TUN_IDIV_TUN, { 24, 12, 8, 6, 6, 4 } },
165 { CGU_TUN_IDIV_ROM, { 4, 4, 4, 4, 5, 4 } },
166 { CGU_TUN_IDIV_PWM, { 8, 8, 8, 8, 10, 8 } },
167 { /* last one */ }
168 }
169};
170
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300171static const struct hsdk_div_full_cfg axi_clk_cfg = {
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300172 { 200000000, 400000000, 600000000, 800000000 },
173 { 800000000, 800000000, 600000000, 800000000 }, {
174 { CGU_SYS_IDIV_APB, { 4, 4, 3, 4 } }, /* APB */
175 { CGU_SYS_IDIV_AXI, { 4, 2, 1, 1 } }, /* AXI */
176 { CGU_SYS_IDIV_ETH, { 2, 2, 2, 2 } }, /* ETH */
177 { CGU_SYS_IDIV_USB, { 2, 2, 2, 2 } }, /* USB */
178 { CGU_SYS_IDIV_SDIO, { 2, 2, 2, 2 } }, /* SDIO */
179 { CGU_SYS_IDIV_HDMI, { 2, 2, 2, 2 } }, /* HDMI */
180 { CGU_SYS_IDIV_GFX_CORE, { 1, 1, 1, 1 } }, /* GPU-CORE */
181 { CGU_SYS_IDIV_GFX_DMA, { 2, 2, 2, 2 } }, /* GPU-DMA */
182 { CGU_SYS_IDIV_GFX_CFG, { 4, 4, 3, 4 } }, /* GPU-CFG */
183 { CGU_SYS_IDIV_DMAC_CORE,{ 2, 2, 2, 2 } }, /* DMAC-CORE */
184 { CGU_SYS_IDIV_DMAC_CFG, { 4, 4, 3, 4 } }, /* DMAC-CFG */
185 { CGU_SYS_IDIV_SDIO_REF, { 8, 8, 6, 8 } }, /* SDIO-REF */
186 { CGU_SYS_IDIV_SPI_REF, { 24, 24, 18, 24 } }, /* SPI-REF */
187 { CGU_SYS_IDIV_I2C_REF, { 4, 4, 3, 4 } }, /* I2C-REF */
188 { CGU_SYS_IDIV_UART_REF, { 24, 24, 18, 24 } }, /* UART-REF */
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300189 { CGU_SYS_IDIV_EBI_REF, { 16, 16, 12, 16 } }, /* EBI-REF */
190 { /* last one */ }
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300191 }
192};
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300193
194struct hsdk_pll_cfg {
Eugeniy Paltsev0b8ac7c2020-05-07 17:52:11 +0300195 const u32 rate;
196 const u8 idiv;
197 const u8 fbdiv;
198 const u8 odiv;
199 const u8 band;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300200};
201
202static const struct hsdk_pll_cfg asdt_pll_cfg[] = {
203 { 100000000, 0, 11, 3, 0 },
204 { 125000000, 0, 14, 3, 0 },
205 { 133000000, 0, 15, 3, 0 },
206 { 150000000, 0, 17, 3, 0 },
207 { 200000000, 1, 47, 3, 0 },
208 { 233000000, 1, 27, 2, 0 },
209 { 300000000, 1, 35, 2, 0 },
210 { 333000000, 1, 39, 2, 0 },
211 { 400000000, 1, 47, 2, 0 },
212 { 500000000, 0, 14, 1, 0 },
213 { 600000000, 0, 17, 1, 0 },
214 { 700000000, 0, 20, 1, 0 },
Eugeniy Paltsevc6f15de2020-04-16 22:35:11 +0300215 { 750000000, 1, 44, 1, 0 },
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300216 { 800000000, 0, 23, 1, 0 },
217 { 900000000, 1, 26, 0, 0 },
218 { 1000000000, 1, 29, 0, 0 },
219 { 1100000000, 1, 32, 0, 0 },
220 { 1200000000, 1, 35, 0, 0 },
221 { 1300000000, 1, 38, 0, 0 },
222 { 1400000000, 1, 41, 0, 0 },
223 { 1500000000, 1, 44, 0, 0 },
224 { 1600000000, 1, 47, 0, 0 },
225 {}
226};
227
228static const struct hsdk_pll_cfg hdmi_pll_cfg[] = {
229 { 297000000, 0, 21, 2, 0 },
230 { 540000000, 0, 19, 1, 0 },
231 { 594000000, 0, 21, 1, 0 },
232 {}
233};
234
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300235struct hsdk_cgu_domain {
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300236 /* PLLs registers */
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300237 void __iomem *pll_regs;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300238 /* PLLs special registers */
239 void __iomem *spec_regs;
240 /* PLLs devdata */
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300241 const struct hsdk_pll_devdata *pll;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300242
243 /* Dividers registers */
244 void __iomem *idiv_regs;
245};
246
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300247struct hsdk_cgu_clk {
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300248 const struct cgu_clk_map *map;
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300249 /* CGU block register */
250 void __iomem *cgu_regs;
251 /* CREG block register */
252 void __iomem *creg_regs;
253
254 /* The domain we are working with */
255 struct hsdk_cgu_domain curr_domain;
256};
257
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300258struct hsdk_pll_devdata {
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300259 const u32 parent_rate;
Eugeniy Paltsev0b8ac7c2020-05-07 17:52:11 +0300260 const struct hsdk_pll_cfg *const pll_cfg;
261 const int (*const update_rate)(struct hsdk_cgu_clk *clk,
262 unsigned long rate,
263 const struct hsdk_pll_cfg *cfg);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300264};
265
266static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *, unsigned long,
267 const struct hsdk_pll_cfg *);
268static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *, unsigned long,
269 const struct hsdk_pll_cfg *);
270
271static const struct hsdk_pll_devdata core_pll_dat = {
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300272 .parent_rate = PARENT_RATE_33,
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300273 .pll_cfg = asdt_pll_cfg,
274 .update_rate = hsdk_pll_core_update_rate,
275};
276
277static const struct hsdk_pll_devdata sdt_pll_dat = {
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300278 .parent_rate = PARENT_RATE_33,
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300279 .pll_cfg = asdt_pll_cfg,
280 .update_rate = hsdk_pll_comm_update_rate,
281};
282
283static const struct hsdk_pll_devdata hdmi_pll_dat = {
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300284 .parent_rate = PARENT_RATE_27,
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300285 .pll_cfg = hdmi_pll_cfg,
286 .update_rate = hsdk_pll_comm_update_rate,
287};
288
289static ulong idiv_set(struct clk *, ulong);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300290static ulong cpu_clk_set(struct clk *, ulong);
291static ulong axi_clk_set(struct clk *, ulong);
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300292static ulong tun_hsdk_set(struct clk *, ulong);
293static ulong tun_h4xd_set(struct clk *, ulong);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300294static ulong idiv_get(struct clk *);
295static int idiv_off(struct clk *);
296static ulong pll_set(struct clk *, ulong);
297static ulong pll_get(struct clk *);
298
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300299struct cgu_clk_map {
Eugeniy Paltsev0b8ac7c2020-05-07 17:52:11 +0300300 const u32 cgu_pll_oft;
301 const u32 cgu_div_oft;
302 const struct hsdk_pll_devdata *const pll_devdata;
303 const ulong (*const get_rate)(struct clk *clk);
304 const ulong (*const set_rate)(struct clk *clk, ulong rate);
305 const int (*const disable)(struct clk *clk);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300306};
307
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300308static const struct cgu_clk_map hsdk_clk_map[] = {
Eugeniy Paltsev7aa8c092020-05-07 20:31:01 +0300309 [CLK_ARC_PLL] = { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
310 [CLK_ARC] = { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
311 [CLK_DDR_PLL] = { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
312 [CLK_SYS_PLL] = { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
313 [CLK_SYS_APB] = { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
314 [CLK_SYS_AXI] = { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
315 [CLK_SYS_ETH] = { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
316 [CLK_SYS_USB] = { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
317 [CLK_SYS_SDIO] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
318 [CLK_SYS_HDMI] = { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
319 [CLK_SYS_GFX_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
320 [CLK_SYS_GFX_DMA] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_DMA, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
321 [CLK_SYS_GFX_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
322 [CLK_SYS_DMAC_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
323 [CLK_SYS_DMAC_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
324 [CLK_SYS_SDIO_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
325 [CLK_SYS_SPI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
326 [CLK_SYS_I2C_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
327 [CLK_SYS_UART_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
328 [CLK_SYS_EBI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
329 [CLK_TUN_PLL] = { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300330 [CLK_TUN_TUN] = { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_hsdk_set, idiv_off },
Eugeniy Paltsev7aa8c092020-05-07 20:31:01 +0300331 [CLK_TUN_ROM] = { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
332 [CLK_TUN_PWM] = { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300333 [CLK_TUN_TIMER] = { /* missing in HSDK */ },
334 [CLK_HDMI_PLL] = { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
335 [CLK_HDMI] = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
336};
337
338static const struct cgu_clk_map hsdk_4xd_clk_map[] = {
339 [CLK_ARC_PLL] = { CGU_ARC_PLL, 0, &core_pll_dat, pll_get, pll_set, NULL },
340 [CLK_ARC] = { CGU_ARC_PLL, CGU_ARC_IDIV, &core_pll_dat, idiv_get, cpu_clk_set, idiv_off },
341 [CLK_DDR_PLL] = { CGU_DDR_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
342 [CLK_SYS_PLL] = { CGU_SYS_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
343 [CLK_SYS_APB] = { CGU_SYS_PLL, CGU_SYS_IDIV_APB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
344 [CLK_SYS_AXI] = { CGU_SYS_PLL, CGU_SYS_IDIV_AXI, &sdt_pll_dat, idiv_get, axi_clk_set, idiv_off },
345 [CLK_SYS_ETH] = { CGU_SYS_PLL, CGU_SYS_IDIV_ETH, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
346 [CLK_SYS_USB] = { CGU_SYS_PLL, CGU_SYS_IDIV_USB, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
347 [CLK_SYS_SDIO] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
348 [CLK_SYS_HDMI] = { CGU_SYS_PLL, CGU_SYS_IDIV_HDMI, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
349 [CLK_SYS_GFX_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_GFX_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
350 [CLK_SYS_GFX_DMA] = { /* missing in HSDK-4xD */ },
351 [CLK_SYS_GFX_CFG] = { /* missing in HSDK-4xD */ },
352 [CLK_SYS_DMAC_CORE] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CORE, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
353 [CLK_SYS_DMAC_CFG] = { CGU_SYS_PLL, CGU_SYS_IDIV_DMAC_CFG, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
354 [CLK_SYS_SDIO_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SDIO_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
355 [CLK_SYS_SPI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_SPI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
356 [CLK_SYS_I2C_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_I2C_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
357 [CLK_SYS_UART_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_UART_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
358 [CLK_SYS_EBI_REF] = { CGU_SYS_PLL, CGU_SYS_IDIV_EBI_REF, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
359 [CLK_TUN_PLL] = { CGU_TUN_PLL, 0, &sdt_pll_dat, pll_get, pll_set, NULL },
360 [CLK_TUN_TUN] = { CGU_TUN_PLL, CGU_TUN_IDIV_TUN, &sdt_pll_dat, idiv_get, tun_h4xd_set, idiv_off },
361 [CLK_TUN_ROM] = { CGU_TUN_PLL, CGU_TUN_IDIV_ROM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
362 [CLK_TUN_PWM] = { CGU_TUN_PLL, CGU_TUN_IDIV_PWM, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
Eugeniy Paltsev7aa8c092020-05-07 20:31:01 +0300363 [CLK_TUN_TIMER] = { CGU_TUN_PLL, CGU_TUN_IDIV_TIMER, &sdt_pll_dat, idiv_get, idiv_set, idiv_off },
364 [CLK_HDMI_PLL] = { CGU_HDMI_PLL, 0, &hdmi_pll_dat, pll_get, pll_set, NULL },
365 [CLK_HDMI] = { CGU_HDMI_PLL, CGU_HDMI_IDIV_APB, &hdmi_pll_dat, idiv_get, idiv_set, idiv_off }
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300366};
367
368static inline void hsdk_idiv_write(struct hsdk_cgu_clk *clk, u32 val)
369{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300370 iowrite32(val, clk->curr_domain.idiv_regs);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300371}
372
373static inline u32 hsdk_idiv_read(struct hsdk_cgu_clk *clk)
374{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300375 return ioread32(clk->curr_domain.idiv_regs);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300376}
377
378static inline void hsdk_pll_write(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
379{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300380 iowrite32(val, clk->curr_domain.pll_regs + reg);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300381}
382
383static inline u32 hsdk_pll_read(struct hsdk_cgu_clk *clk, u32 reg)
384{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300385 return ioread32(clk->curr_domain.pll_regs + reg);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300386}
387
388static inline void hsdk_pll_spcwrite(struct hsdk_cgu_clk *clk, u32 reg, u32 val)
389{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300390 iowrite32(val, clk->curr_domain.spec_regs + reg);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300391}
392
393static inline u32 hsdk_pll_spcread(struct hsdk_cgu_clk *clk, u32 reg)
394{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300395 return ioread32(clk->curr_domain.spec_regs + reg);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300396}
397
398static inline void hsdk_pll_set_cfg(struct hsdk_cgu_clk *clk,
399 const struct hsdk_pll_cfg *cfg)
400{
401 u32 val = 0;
402
403 /* Powerdown and Bypass bits should be cleared */
Eugeniy Paltsev0b8ac7c2020-05-07 17:52:11 +0300404 val |= (u32)cfg->idiv << CGU_PLL_CTRL_IDIV_SHIFT;
405 val |= (u32)cfg->fbdiv << CGU_PLL_CTRL_FBDIV_SHIFT;
406 val |= (u32)cfg->odiv << CGU_PLL_CTRL_ODIV_SHIFT;
407 val |= (u32)cfg->band << CGU_PLL_CTRL_BAND_SHIFT;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300408
409 pr_debug("write configurarion: %#x\n", val);
410
411 hsdk_pll_write(clk, CGU_PLL_CTRL, val);
412}
413
414static inline bool hsdk_pll_is_locked(struct hsdk_cgu_clk *clk)
415{
416 return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_LOCK);
417}
418
419static inline bool hsdk_pll_is_err(struct hsdk_cgu_clk *clk)
420{
421 return !!(hsdk_pll_read(clk, CGU_PLL_STATUS) & CGU_PLL_STATUS_ERR);
422}
423
424static ulong pll_get(struct clk *sclk)
425{
426 u32 val;
427 u64 rate;
428 u32 idiv, fbdiv, odiv;
429 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300430 u32 parent_rate = clk->curr_domain.pll->parent_rate;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300431
432 val = hsdk_pll_read(clk, CGU_PLL_CTRL);
433
434 pr_debug("current configurarion: %#x\n", val);
435
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300436 /* Check if PLL is bypassed */
437 if (val & CGU_PLL_CTRL_BYPASS)
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300438 return parent_rate;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300439
Eugeniy Paltsev9d70c9c2020-01-29 14:08:29 +0300440 /* Check if PLL is disabled */
441 if (val & CGU_PLL_CTRL_PD)
442 return 0;
443
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300444 /* input divider = reg.idiv + 1 */
445 idiv = 1 + ((val & CGU_PLL_CTRL_IDIV_MASK) >> CGU_PLL_CTRL_IDIV_SHIFT);
446 /* fb divider = 2*(reg.fbdiv + 1) */
447 fbdiv = 2 * (1 + ((val & CGU_PLL_CTRL_FBDIV_MASK) >> CGU_PLL_CTRL_FBDIV_SHIFT));
448 /* output divider = 2^(reg.odiv) */
449 odiv = 1 << ((val & CGU_PLL_CTRL_ODIV_MASK) >> CGU_PLL_CTRL_ODIV_SHIFT);
450
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300451 rate = (u64)parent_rate * fbdiv;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300452 do_div(rate, idiv * odiv);
453
454 return rate;
455}
456
457static unsigned long hsdk_pll_round_rate(struct clk *sclk, unsigned long rate)
458{
459 int i;
460 unsigned long best_rate;
461 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300462 const struct hsdk_pll_cfg *pll_cfg = clk->curr_domain.pll->pll_cfg;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300463
464 if (pll_cfg[0].rate == 0)
465 return -EINVAL;
466
467 best_rate = pll_cfg[0].rate;
468
469 for (i = 1; pll_cfg[i].rate != 0; i++) {
470 if (abs(rate - pll_cfg[i].rate) < abs(rate - best_rate))
471 best_rate = pll_cfg[i].rate;
472 }
473
474 pr_debug("chosen best rate: %lu\n", best_rate);
475
476 return best_rate;
477}
478
479static int hsdk_pll_comm_update_rate(struct hsdk_cgu_clk *clk,
480 unsigned long rate,
481 const struct hsdk_pll_cfg *cfg)
482{
483 hsdk_pll_set_cfg(clk, cfg);
484
485 /*
486 * Wait until CGU relocks and check error status.
487 * If after timeout CGU is unlocked yet return error.
488 */
489 udelay(HSDK_PLL_MAX_LOCK_TIME);
490 if (!hsdk_pll_is_locked(clk))
491 return -ETIMEDOUT;
492
493 if (hsdk_pll_is_err(clk))
494 return -EINVAL;
495
496 return 0;
497}
498
499static int hsdk_pll_core_update_rate(struct hsdk_cgu_clk *clk,
500 unsigned long rate,
501 const struct hsdk_pll_cfg *cfg)
502{
503 /*
504 * When core clock exceeds 500MHz, the divider for the interface
505 * clock must be programmed to div-by-2.
506 */
507 if (rate > CORE_IF_CLK_THRESHOLD_HZ)
508 hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_2);
509
510 hsdk_pll_set_cfg(clk, cfg);
511
512 /*
513 * Wait until CGU relocks and check error status.
514 * If after timeout CGU is unlocked yet return error.
515 */
516 udelay(HSDK_PLL_MAX_LOCK_TIME);
517 if (!hsdk_pll_is_locked(clk))
518 return -ETIMEDOUT;
519
520 if (hsdk_pll_is_err(clk))
521 return -EINVAL;
522
523 /*
524 * Program divider to div-by-1 if we succesfuly set core clock below
525 * 500MHz threshold.
526 */
527 if (rate <= CORE_IF_CLK_THRESHOLD_HZ)
528 hsdk_pll_spcwrite(clk, CREG_CORE_IF_DIV, CREG_CORE_IF_CLK_DIV_1);
529
530 return 0;
531}
532
533static ulong pll_set(struct clk *sclk, ulong rate)
534{
535 int i;
536 unsigned long best_rate;
537 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300538 const struct hsdk_pll_devdata *pll = clk->curr_domain.pll;
539 const struct hsdk_pll_cfg *pll_cfg = pll->pll_cfg;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300540
541 best_rate = hsdk_pll_round_rate(sclk, rate);
542
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300543 for (i = 0; pll_cfg[i].rate != 0; i++)
544 if (pll_cfg[i].rate == best_rate)
545 return pll->update_rate(clk, best_rate, &pll_cfg[i]);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300546
Eugeniy Paltsev5872fc62020-01-29 14:08:30 +0300547 pr_err("invalid rate=%ld Hz, parent_rate=%d Hz\n", best_rate,
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300548 pll->parent_rate);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300549
550 return -EINVAL;
551}
552
553static int idiv_off(struct clk *sclk)
554{
555 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
556
557 hsdk_idiv_write(clk, 0);
558
559 return 0;
560}
561
562static ulong idiv_get(struct clk *sclk)
563{
564 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
565 ulong parent_rate = pll_get(sclk);
566 u32 div_factor = hsdk_idiv_read(clk);
567
568 div_factor &= CGU_IDIV_MASK;
569
570 pr_debug("current configurarion: %#x (%d)\n", div_factor, div_factor);
571
572 if (div_factor == 0)
573 return 0;
574
575 return parent_rate / div_factor;
576}
577
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300578/* Special behavior: wen we set this clock we set both idiv and pll */
579static ulong cpu_clk_set(struct clk *sclk, ulong rate)
580{
581 ulong ret;
582
583 ret = pll_set(sclk, rate);
584 idiv_set(sclk, rate);
585
586 return ret;
587}
588
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300589/*
590 * Special behavior:
591 * when we set these clocks we set both PLL and all idiv dividers related to
592 * this PLL domain.
593 */
594static ulong common_div_clk_set(struct clk *sclk, ulong rate,
595 const struct hsdk_div_full_cfg *cfg)
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300596{
597 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
598 ulong pll_rate;
599 int i, freq_idx = -1;
600 ulong ret = 0;
601
602 pll_rate = pll_get(sclk);
603
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300604 for (i = 0; i < MAX_FREQ_VARIATIONS; i++) {
605 /* unused freq variations are filled with 0 */
606 if (!cfg->clk_rate[i])
607 break;
608
609 if (cfg->clk_rate[i] == rate) {
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300610 freq_idx = i;
611 break;
612 }
613 }
614
615 if (freq_idx < 0) {
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300616 pr_err("clk: invalid rate=%ld Hz\n", rate);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300617 return -EINVAL;
618 }
619
620 /* configure PLL before dividers */
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300621 if (cfg->pll_rate[freq_idx] < pll_rate)
622 ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300623
624 /* configure SYS dividers */
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300625 for (i = 0; cfg->idiv[i].oft != 0; i++) {
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300626 clk->curr_domain.idiv_regs = clk->cgu_regs + cfg->idiv[i].oft;
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300627 hsdk_idiv_write(clk, cfg->idiv[i].val[freq_idx]);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300628 }
629
630 /* configure PLL after dividers */
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300631 if (cfg->pll_rate[freq_idx] >= pll_rate)
632 ret = pll_set(sclk, cfg->pll_rate[freq_idx]);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300633
634 return ret;
635}
636
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300637static ulong axi_clk_set(struct clk *sclk, ulong rate)
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300638{
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300639 return common_div_clk_set(sclk, rate, &axi_clk_cfg);
640}
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300641
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300642static ulong tun_hsdk_set(struct clk *sclk, ulong rate)
643{
644 return common_div_clk_set(sclk, rate, &hsdk_tun_clk_cfg);
645}
646
647static ulong tun_h4xd_set(struct clk *sclk, ulong rate)
Eugeniy Paltsev42da3942020-05-07 16:59:54 +0300648{
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300649 return common_div_clk_set(sclk, rate, &hsdk_4xd_tun_clk_cfg);
Eugeniy Paltsev74514242018-01-16 20:44:25 +0300650}
651
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300652static ulong idiv_set(struct clk *sclk, ulong rate)
653{
654 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
655 ulong parent_rate = pll_get(sclk);
656 u32 div_factor;
657
658 div_factor = parent_rate / rate;
659 if (abs(rate - parent_rate / (div_factor + 1)) <=
660 abs(rate - parent_rate / div_factor)) {
661 div_factor += 1;
662 }
663
664 if (div_factor & ~CGU_IDIV_MASK) {
Eugeniy Paltsev7d7d9f22018-01-16 20:44:27 +0300665 pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: max divider valie is%d\n",
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300666 rate, parent_rate, div_factor, CGU_IDIV_MASK);
667
668 div_factor = CGU_IDIV_MASK;
669 }
670
671 if (div_factor == 0) {
Eugeniy Paltsev7d7d9f22018-01-16 20:44:27 +0300672 pr_err("invalid rate=%ld Hz, parent_rate=%ld Hz, div=%d: min divider valie is 1\n",
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300673 rate, parent_rate, div_factor);
674
675 div_factor = 1;
676 }
677
678 hsdk_idiv_write(clk, div_factor);
679
680 return 0;
681}
682
683static int hsdk_prepare_clock_tree_branch(struct clk *sclk)
684{
685 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
686
687 if (sclk->id >= CGU_MAX_CLOCKS)
688 return -EINVAL;
689
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300690 /* clocks missing in current map have their entry zeroed */
691 if (!clk->map[sclk->id].pll_devdata)
692 return -EINVAL;
693
694 clk->curr_domain.pll = clk->map[sclk->id].pll_devdata;
695 clk->curr_domain.pll_regs = clk->cgu_regs + clk->map[sclk->id].cgu_pll_oft;
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300696 clk->curr_domain.spec_regs = clk->creg_regs;
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300697 clk->curr_domain.idiv_regs = clk->cgu_regs + clk->map[sclk->id].cgu_div_oft;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300698
699 return 0;
700}
701
702static ulong hsdk_cgu_get_rate(struct clk *sclk)
703{
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300704 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
705
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300706 if (hsdk_prepare_clock_tree_branch(sclk))
707 return -EINVAL;
708
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300709 return clk->map[sclk->id].get_rate(sclk);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300710}
711
712static ulong hsdk_cgu_set_rate(struct clk *sclk, ulong rate)
713{
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300714 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
715
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300716 if (hsdk_prepare_clock_tree_branch(sclk))
717 return -EINVAL;
718
Eugeniy Paltsev87b0d192020-05-07 20:18:41 +0300719 if (clk->map[sclk->id].set_rate)
720 return clk->map[sclk->id].set_rate(sclk, rate);
721
Simon Glass29ff16a2021-03-25 10:26:08 +1300722 return -EINVAL;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300723}
724
725static int hsdk_cgu_disable(struct clk *sclk)
726{
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300727 struct hsdk_cgu_clk *clk = dev_get_priv(sclk->dev);
728
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300729 if (hsdk_prepare_clock_tree_branch(sclk))
730 return -EINVAL;
731
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300732 if (clk->map[sclk->id].disable)
733 return clk->map[sclk->id].disable(sclk);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300734
Simon Glass29ff16a2021-03-25 10:26:08 +1300735 return -EINVAL;
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300736}
737
738static const struct clk_ops hsdk_cgu_ops = {
739 .set_rate = hsdk_cgu_set_rate,
740 .get_rate = hsdk_cgu_get_rate,
741 .disable = hsdk_cgu_disable,
742};
743
744static int hsdk_cgu_clk_probe(struct udevice *dev)
745{
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300746 struct hsdk_cgu_clk *hsdk_clk = dev_get_priv(dev);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300747
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300748 BUILD_BUG_ON(ARRAY_SIZE(hsdk_clk_map) != CGU_MAX_CLOCKS);
749 BUILD_BUG_ON(ARRAY_SIZE(hsdk_4xd_clk_map) != CGU_MAX_CLOCKS);
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300750
Eugeniy Paltsev6bd63fc2020-05-07 22:20:10 +0300751 /* Choose which clock map to use in runtime */
752 if ((read_aux_reg(ARC_AUX_IDENTITY) & 0xFF) == 0x52)
753 hsdk_clk->map = hsdk_clk_map;
754 else
755 hsdk_clk->map = hsdk_4xd_clk_map;
Eugeniy Paltsev089c8e92020-05-07 20:10:30 +0300756
Johan Jonkerb52189e2023-03-13 01:32:31 +0100757 hsdk_clk->cgu_regs = devfdt_get_addr_index_ptr(dev, 0);
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300758 if (!hsdk_clk->cgu_regs)
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300759 return -EINVAL;
760
Johan Jonkerb52189e2023-03-13 01:32:31 +0100761 hsdk_clk->creg_regs = devfdt_get_addr_index_ptr(dev, 1);
Eugeniy Paltsev9264fdf2020-05-07 19:00:08 +0300762 if (!hsdk_clk->creg_regs)
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300763 return -EINVAL;
764
765 return 0;
766}
767
768static const struct udevice_id hsdk_cgu_clk_id[] = {
769 { .compatible = "snps,hsdk-cgu-clock" },
770 { }
771};
772
773U_BOOT_DRIVER(hsdk_cgu_clk) = {
774 .name = "hsdk-cgu-clk",
775 .id = UCLASS_CLK,
776 .of_match = hsdk_cgu_clk_id,
777 .probe = hsdk_cgu_clk_probe,
Simon Glass8a2b47f2020-12-03 16:55:17 -0700778 .priv_auto = sizeof(struct hsdk_cgu_clk),
Eugeniy Paltsev7e1fb092017-12-10 21:20:08 +0300779 .ops = &hsdk_cgu_ops,
780};