aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/clk/imx/clk-imx8mq.c53
-rw-r--r--drivers/clk/imx/clk-sccg-pll.c514
-rw-r--r--drivers/clk/imx/clk.h9
3 files changed, 417 insertions, 159 deletions
diff --git a/drivers/clk/imx/clk-imx8mq.c b/drivers/clk/imx/clk-imx8mq.c
index 01c771f441cb..081dc2d7c99c 100644
--- a/drivers/clk/imx/clk-imx8mq.c
+++ b/drivers/clk/imx/clk-imx8mq.c
@@ -34,15 +34,10 @@ static const char * const audio_pll1_bypass_sels[] = {"audio_pll1", "audio_pll1_
34static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", }; 34static const char * const audio_pll2_bypass_sels[] = {"audio_pll2", "audio_pll2_ref_sel", };
35static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", }; 35static const char * const video_pll1_bypass_sels[] = {"video_pll1", "video_pll1_ref_sel", };
36 36
37static const char * const sys1_pll1_out_sels[] = {"sys1_pll1", "sys1_pll1_ref_sel", }; 37static const char * const sys1_pll_out_sels[] = {"sys1_pll1_ref_sel", };
38static const char * const sys2_pll1_out_sels[] = {"sys2_pll1", "sys1_pll1_ref_sel", }; 38static const char * const sys2_pll_out_sels[] = {"sys1_pll1_ref_sel", "sys2_pll1_ref_sel", };
39static const char * const sys3_pll1_out_sels[] = {"sys3_pll1", "sys3_pll1_ref_sel", }; 39static const char * const sys3_pll_out_sels[] = {"sys3_pll1_ref_sel", "sys2_pll1_ref_sel", };
40static const char * const dram_pll1_out_sels[] = {"dram_pll1", "dram_pll1_ref_sel", }; 40static const char * const dram_pll_out_sels[] = {"dram_pll1_ref_sel", };
41
42static const char * const sys1_pll2_out_sels[] = {"sys1_pll2_div", "sys1_pll1_ref_sel", };
43static const char * const sys2_pll2_out_sels[] = {"sys2_pll2_div", "sys2_pll1_ref_sel", };
44static const char * const sys3_pll2_out_sels[] = {"sys3_pll2_div", "sys2_pll1_ref_sel", };
45static const char * const dram_pll2_out_sels[] = {"dram_pll2_div", "dram_pll1_ref_sel", };
46 41
47/* CCM ROOT */ 42/* CCM ROOT */
48static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m", 43static const char * const imx8mq_a53_sels[] = {"osc_25m", "arm_pll_out", "sys2_pll_500m", "sys2_pll_1000m",
@@ -313,10 +308,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
313 clks[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6); 308 clks[IMX8MQ_AUDIO_PLL1_REF_DIV] = imx_clk_divider("audio_pll1_ref_div", "audio_pll1_ref_sel", base + 0x0, 5, 6);
314 clks[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6); 309 clks[IMX8MQ_AUDIO_PLL2_REF_DIV] = imx_clk_divider("audio_pll2_ref_div", "audio_pll2_ref_sel", base + 0x8, 5, 6);
315 clks[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6); 310 clks[IMX8MQ_VIDEO_PLL1_REF_DIV] = imx_clk_divider("video_pll1_ref_div", "video_pll1_ref_sel", base + 0x10, 5, 6);
316 clks[IMX8MQ_SYS1_PLL1_REF_DIV] = imx_clk_divider("sys1_pll1_ref_div", "sys1_pll1_ref_sel", base + 0x38, 25, 3);
317 clks[IMX8MQ_SYS2_PLL1_REF_DIV] = imx_clk_divider("sys2_pll1_ref_div", "sys2_pll1_ref_sel", base + 0x44, 25, 3);
318 clks[IMX8MQ_SYS3_PLL1_REF_DIV] = imx_clk_divider("sys3_pll1_ref_div", "sys3_pll1_ref_sel", base + 0x50, 25, 3);
319 clks[IMX8MQ_DRAM_PLL1_REF_DIV] = imx_clk_divider("dram_pll1_ref_div", "dram_pll1_ref_sel", base + 0x68, 25, 3);
320 311
321 clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28); 312 clks[IMX8MQ_ARM_PLL] = imx_clk_frac_pll("arm_pll", "arm_pll_ref_div", base + 0x28);
322 clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18); 313 clks[IMX8MQ_GPU_PLL] = imx_clk_frac_pll("gpu_pll", "gpu_pll_ref_div", base + 0x18);
@@ -324,25 +315,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
324 clks[IMX8MQ_AUDIO_PLL1] = imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0); 315 clks[IMX8MQ_AUDIO_PLL1] = imx_clk_frac_pll("audio_pll1", "audio_pll1_ref_div", base + 0x0);
325 clks[IMX8MQ_AUDIO_PLL2] = imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8); 316 clks[IMX8MQ_AUDIO_PLL2] = imx_clk_frac_pll("audio_pll2", "audio_pll2_ref_div", base + 0x8);
326 clks[IMX8MQ_VIDEO_PLL1] = imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10); 317 clks[IMX8MQ_VIDEO_PLL1] = imx_clk_frac_pll("video_pll1", "video_pll1_ref_div", base + 0x10);
327 clks[IMX8MQ_SYS1_PLL1] = imx_clk_sccg_pll("sys1_pll1", "sys1_pll1_ref_div", base + 0x30, SCCG_PLL1);
328 clks[IMX8MQ_SYS2_PLL1] = imx_clk_sccg_pll("sys2_pll1", "sys2_pll1_ref_div", base + 0x3c, SCCG_PLL1);
329 clks[IMX8MQ_SYS3_PLL1] = imx_clk_sccg_pll("sys3_pll1", "sys3_pll1_ref_div", base + 0x48, SCCG_PLL1);
330 clks[IMX8MQ_DRAM_PLL1] = imx_clk_sccg_pll("dram_pll1", "dram_pll1_ref_div", base + 0x60, SCCG_PLL1);
331
332 clks[IMX8MQ_SYS1_PLL2] = imx_clk_sccg_pll("sys1_pll2", "sys1_pll1_out_div", base + 0x30, SCCG_PLL2);
333 clks[IMX8MQ_SYS2_PLL2] = imx_clk_sccg_pll("sys2_pll2", "sys2_pll1_out_div", base + 0x3c, SCCG_PLL2);
334 clks[IMX8MQ_SYS3_PLL2] = imx_clk_sccg_pll("sys3_pll2", "sys3_pll1_out_div", base + 0x48, SCCG_PLL2);
335 clks[IMX8MQ_DRAM_PLL2] = imx_clk_sccg_pll("dram_pll2", "dram_pll1_out_div", base + 0x60, SCCG_PLL2);
336
337 /* PLL divs */
338 clks[IMX8MQ_SYS1_PLL1_OUT_DIV] = imx_clk_divider("sys1_pll1_out_div", "sys1_pll1_out", base + 0x38, 19, 6);
339 clks[IMX8MQ_SYS2_PLL1_OUT_DIV] = imx_clk_divider("sys2_pll1_out_div", "sys2_pll1_out", base + 0x44, 19, 6);
340 clks[IMX8MQ_SYS3_PLL1_OUT_DIV] = imx_clk_divider("sys3_pll1_out_div", "sys3_pll1_out", base + 0x50, 19, 6);
341 clks[IMX8MQ_DRAM_PLL1_OUT_DIV] = imx_clk_divider("dram_pll1_out_div", "dram_pll1_out", base + 0x68, 19, 6);
342 clks[IMX8MQ_SYS1_PLL2_DIV] = imx_clk_divider("sys1_pll2_div", "sys1_pll2", base + 0x38, 1, 6);
343 clks[IMX8MQ_SYS2_PLL2_DIV] = imx_clk_divider("sys2_pll2_div", "sys2_pll2", base + 0x44, 1, 6);
344 clks[IMX8MQ_SYS3_PLL2_DIV] = imx_clk_divider("sys3_pll2_div", "sys3_pll2", base + 0x50, 1, 6);
345 clks[IMX8MQ_DRAM_PLL2_DIV] = imx_clk_divider("dram_pll2_div", "dram_pll2", base + 0x68, 1, 6);
346 318
347 /* PLL bypass out */ 319 /* PLL bypass out */
348 clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT); 320 clks[IMX8MQ_ARM_PLL_BYPASS] = imx_clk_mux_flags("arm_pll_bypass", base + 0x28, 14, 1, arm_pll_bypass_sels, ARRAY_SIZE(arm_pll_bypass_sels), CLK_SET_RATE_PARENT);
@@ -352,15 +324,6 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
352 clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels)); 324 clks[IMX8MQ_AUDIO_PLL2_BYPASS] = imx_clk_mux("audio_pll2_bypass", base + 0x8, 14, 1, audio_pll2_bypass_sels, ARRAY_SIZE(audio_pll2_bypass_sels));
353 clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels)); 325 clks[IMX8MQ_VIDEO_PLL1_BYPASS] = imx_clk_mux("video_pll1_bypass", base + 0x10, 14, 1, video_pll1_bypass_sels, ARRAY_SIZE(video_pll1_bypass_sels));
354 326
355 clks[IMX8MQ_SYS1_PLL1_OUT] = imx_clk_mux("sys1_pll1_out", base + 0x30, 5, 1, sys1_pll1_out_sels, ARRAY_SIZE(sys1_pll1_out_sels));
356 clks[IMX8MQ_SYS2_PLL1_OUT] = imx_clk_mux("sys2_pll1_out", base + 0x3c, 5, 1, sys2_pll1_out_sels, ARRAY_SIZE(sys2_pll1_out_sels));
357 clks[IMX8MQ_SYS3_PLL1_OUT] = imx_clk_mux("sys3_pll1_out", base + 0x48, 5, 1, sys3_pll1_out_sels, ARRAY_SIZE(sys3_pll1_out_sels));
358 clks[IMX8MQ_DRAM_PLL1_OUT] = imx_clk_mux("dram_pll1_out", base + 0x60, 5, 1, dram_pll1_out_sels, ARRAY_SIZE(dram_pll1_out_sels));
359 clks[IMX8MQ_SYS1_PLL2_OUT] = imx_clk_mux("sys1_pll2_out", base + 0x30, 4, 1, sys1_pll2_out_sels, ARRAY_SIZE(sys1_pll2_out_sels));
360 clks[IMX8MQ_SYS2_PLL2_OUT] = imx_clk_mux("sys2_pll2_out", base + 0x3c, 4, 1, sys2_pll2_out_sels, ARRAY_SIZE(sys2_pll2_out_sels));
361 clks[IMX8MQ_SYS3_PLL2_OUT] = imx_clk_mux("sys3_pll2_out", base + 0x48, 4, 1, sys3_pll2_out_sels, ARRAY_SIZE(sys3_pll2_out_sels));
362 clks[IMX8MQ_DRAM_PLL2_OUT] = imx_clk_mux("dram_pll2_out", base + 0x60, 4, 1, dram_pll2_out_sels, ARRAY_SIZE(dram_pll2_out_sels));
363
364 /* PLL OUT GATE */ 327 /* PLL OUT GATE */
365 clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21); 328 clks[IMX8MQ_ARM_PLL_OUT] = imx_clk_gate("arm_pll_out", "arm_pll_bypass", base + 0x28, 21);
366 clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21); 329 clks[IMX8MQ_GPU_PLL_OUT] = imx_clk_gate("gpu_pll_out", "gpu_pll_bypass", base + 0x18, 21);
@@ -368,11 +331,11 @@ static int imx8mq_clocks_probe(struct platform_device *pdev)
368 clks[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21); 331 clks[IMX8MQ_AUDIO_PLL1_OUT] = imx_clk_gate("audio_pll1_out", "audio_pll1_bypass", base + 0x0, 21);
369 clks[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21); 332 clks[IMX8MQ_AUDIO_PLL2_OUT] = imx_clk_gate("audio_pll2_out", "audio_pll2_bypass", base + 0x8, 21);
370 clks[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21); 333 clks[IMX8MQ_VIDEO_PLL1_OUT] = imx_clk_gate("video_pll1_out", "video_pll1_bypass", base + 0x10, 21);
371 clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_gate("sys1_pll_out", "sys1_pll2_out", base + 0x30, 9);
372 clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_gate("sys2_pll_out", "sys2_pll2_out", base + 0x3c, 9);
373 clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_gate("sys3_pll_out", "sys3_pll2_out", base + 0x48, 9);
374 clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_gate("dram_pll_out", "dram_pll2_out", base + 0x60, 9);
375 334
335 clks[IMX8MQ_SYS1_PLL_OUT] = imx_clk_sccg_pll("sys1_pll_out", sys1_pll_out_sels, ARRAY_SIZE(sys1_pll_out_sels), 0, 0, 0, base + 0x30, CLK_IS_CRITICAL);
336 clks[IMX8MQ_SYS2_PLL_OUT] = imx_clk_sccg_pll("sys2_pll_out", sys2_pll_out_sels, ARRAY_SIZE(sys2_pll_out_sels), 0, 0, 1, base + 0x3c, CLK_IS_CRITICAL);
337 clks[IMX8MQ_SYS3_PLL_OUT] = imx_clk_sccg_pll("sys3_pll_out", sys3_pll_out_sels, ARRAY_SIZE(sys3_pll_out_sels), 0, 0, 1, base + 0x48, CLK_IS_CRITICAL);
338 clks[IMX8MQ_DRAM_PLL_OUT] = imx_clk_sccg_pll("dram_pll_out", dram_pll_out_sels, ARRAY_SIZE(dram_pll_out_sels), 0, 0, 0, base + 0x60, CLK_IS_CRITICAL);
376 /* SYS PLL fixed output */ 339 /* SYS PLL fixed output */
377 clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20); 340 clks[IMX8MQ_SYS1_PLL_40M] = imx_clk_fixed_factor("sys1_pll_40m", "sys1_pll_out", 1, 20);
378 clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10); 341 clks[IMX8MQ_SYS1_PLL_80M] = imx_clk_fixed_factor("sys1_pll_80m", "sys1_pll_out", 1, 10);
diff --git a/drivers/clk/imx/clk-sccg-pll.c b/drivers/clk/imx/clk-sccg-pll.c
index ee7752bace89..9dfd03a95557 100644
--- a/drivers/clk/imx/clk-sccg-pll.c
+++ b/drivers/clk/imx/clk-sccg-pll.c
@@ -25,87 +25,292 @@
25#define PLL_DIVF2_MASK GENMASK(12, 7) 25#define PLL_DIVF2_MASK GENMASK(12, 7)
26#define PLL_DIVR1_MASK GENMASK(27, 25) 26#define PLL_DIVR1_MASK GENMASK(27, 25)
27#define PLL_DIVR2_MASK GENMASK(24, 19) 27#define PLL_DIVR2_MASK GENMASK(24, 19)
28#define PLL_DIVQ_MASK GENMASK(6, 1)
28#define PLL_REF_MASK GENMASK(2, 0) 29#define PLL_REF_MASK GENMASK(2, 0)
29 30
30#define PLL_LOCK_MASK BIT(31) 31#define PLL_LOCK_MASK BIT(31)
31#define PLL_PD_MASK BIT(7) 32#define PLL_PD_MASK BIT(7)
32 33
33#define OSC_25M 25000000 34/* These are the specification limits for the SSCG PLL */
34#define OSC_27M 27000000 35#define PLL_REF_MIN_FREQ 25000000UL
36#define PLL_REF_MAX_FREQ 235000000UL
35 37
36#define PLL_SCCG_LOCK_TIMEOUT 70 38#define PLL_STAGE1_MIN_FREQ 1600000000UL
39#define PLL_STAGE1_MAX_FREQ 2400000000UL
40
41#define PLL_STAGE1_REF_MIN_FREQ 25000000UL
42#define PLL_STAGE1_REF_MAX_FREQ 54000000UL
43
44#define PLL_STAGE2_MIN_FREQ 1200000000UL
45#define PLL_STAGE2_MAX_FREQ 2400000000UL
46
47#define PLL_STAGE2_REF_MIN_FREQ 54000000UL
48#define PLL_STAGE2_REF_MAX_FREQ 75000000UL
49
50#define PLL_OUT_MIN_FREQ 20000000UL
51#define PLL_OUT_MAX_FREQ 1200000000UL
52
53#define PLL_DIVR1_MAX 7
54#define PLL_DIVR2_MAX 63
55#define PLL_DIVF1_MAX 63
56#define PLL_DIVF2_MAX 63
57#define PLL_DIVQ_MAX 63
58
59#define PLL_BYPASS_NONE 0x0
60#define PLL_BYPASS1 0x2
61#define PLL_BYPASS2 0x1
62
63#define SSCG_PLL_BYPASS1_MASK BIT(5)
64#define SSCG_PLL_BYPASS2_MASK BIT(4)
65#define SSCG_PLL_BYPASS_MASK GENMASK(5, 4)
66
67#define PLL_SCCG_LOCK_TIMEOUT 70
68
69struct clk_sccg_pll_setup {
70 int divr1, divf1;
71 int divr2, divf2;
72 int divq;
73 int bypass;
74
75 uint64_t vco1;
76 uint64_t vco2;
77 uint64_t fout;
78 uint64_t ref;
79 uint64_t ref_div1;
80 uint64_t ref_div2;
81 uint64_t fout_request;
82 int fout_error;
83};
37 84
38struct clk_sccg_pll { 85struct clk_sccg_pll {
39 struct clk_hw hw; 86 struct clk_hw hw;
40 void __iomem *base; 87 const struct clk_ops ops;
88
89 void __iomem *base;
90
91 struct clk_sccg_pll_setup setup;
92
93 u8 parent;
94 u8 bypass1;
95 u8 bypass2;
41}; 96};
42 97
43#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw) 98#define to_clk_sccg_pll(_hw) container_of(_hw, struct clk_sccg_pll, hw)
44 99
45static int clk_pll_wait_lock(struct clk_sccg_pll *pll) 100static int clk_sccg_pll_wait_lock(struct clk_sccg_pll *pll)
46{ 101{
47 u32 val; 102 u32 val;
48 103
49 return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK, 0, 104 val = readl_relaxed(pll->base + PLL_CFG0);
50 PLL_SCCG_LOCK_TIMEOUT); 105
106 /* don't wait for lock if all plls are bypassed */
107 if (!(val & SSCG_PLL_BYPASS2_MASK))
108 return readl_poll_timeout(pll->base, val, val & PLL_LOCK_MASK,
109 0, PLL_SCCG_LOCK_TIMEOUT);
110
111 return 0;
51} 112}
52 113
53static int clk_pll1_is_prepared(struct clk_hw *hw) 114static int clk_sccg_pll2_check_match(struct clk_sccg_pll_setup *setup,
115 struct clk_sccg_pll_setup *temp_setup)
54{ 116{
55 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 117 int new_diff = temp_setup->fout - temp_setup->fout_request;
56 u32 val; 118 int diff = temp_setup->fout_error;
57 119
58 val = readl_relaxed(pll->base + PLL_CFG0); 120 if (abs(diff) > abs(new_diff)) {
59 return (val & PLL_PD_MASK) ? 0 : 1; 121 temp_setup->fout_error = new_diff;
122 memcpy(setup, temp_setup, sizeof(struct clk_sccg_pll_setup));
123
124 if (temp_setup->fout_request == temp_setup->fout)
125 return 0;
126 }
127 return -1;
60} 128}
61 129
62static unsigned long clk_pll1_recalc_rate(struct clk_hw *hw, 130static int clk_sccg_divq_lookup(struct clk_sccg_pll_setup *setup,
63 unsigned long parent_rate) 131 struct clk_sccg_pll_setup *temp_setup)
64{ 132{
65 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 133 int ret = -EINVAL;
66 u32 val, divf; 134
135 for (temp_setup->divq = 0; temp_setup->divq <= PLL_DIVQ_MAX;
136 temp_setup->divq++) {
137 temp_setup->vco2 = temp_setup->vco1;
138 do_div(temp_setup->vco2, temp_setup->divr2 + 1);
139 temp_setup->vco2 *= 2;
140 temp_setup->vco2 *= temp_setup->divf2 + 1;
141 if (temp_setup->vco2 >= PLL_STAGE2_MIN_FREQ &&
142 temp_setup->vco2 <= PLL_STAGE2_MAX_FREQ) {
143 temp_setup->fout = temp_setup->vco2;
144 do_div(temp_setup->fout, 2 * (temp_setup->divq + 1));
145
146 ret = clk_sccg_pll2_check_match(setup, temp_setup);
147 if (!ret) {
148 temp_setup->bypass = PLL_BYPASS1;
149 return ret;
150 }
151 }
152 }
67 153
68 val = readl_relaxed(pll->base + PLL_CFG2); 154 return ret;
69 divf = FIELD_GET(PLL_DIVF1_MASK, val); 155}
156
157static int clk_sccg_divf2_lookup(struct clk_sccg_pll_setup *setup,
158 struct clk_sccg_pll_setup *temp_setup)
159{
160 int ret = -EINVAL;
161
162 for (temp_setup->divf2 = 0; temp_setup->divf2 <= PLL_DIVF2_MAX;
163 temp_setup->divf2++) {
164 ret = clk_sccg_divq_lookup(setup, temp_setup);
165 if (!ret)
166 return ret;
167 }
70 168
71 return parent_rate * 2 * (divf + 1); 169 return ret;
72} 170}
73 171
74static long clk_pll1_round_rate(struct clk_hw *hw, unsigned long rate, 172static int clk_sccg_divr2_lookup(struct clk_sccg_pll_setup *setup,
75 unsigned long *prate) 173 struct clk_sccg_pll_setup *temp_setup)
76{ 174{
77 unsigned long parent_rate = *prate; 175 int ret = -EINVAL;
78 u32 div; 176
177 for (temp_setup->divr2 = 0; temp_setup->divr2 <= PLL_DIVR2_MAX;
178 temp_setup->divr2++) {
179 temp_setup->ref_div2 = temp_setup->vco1;
180 do_div(temp_setup->ref_div2, temp_setup->divr2 + 1);
181 if (temp_setup->ref_div2 >= PLL_STAGE2_REF_MIN_FREQ &&
182 temp_setup->ref_div2 <= PLL_STAGE2_REF_MAX_FREQ) {
183 ret = clk_sccg_divf2_lookup(setup, temp_setup);
184 if (!ret)
185 return ret;
186 }
187 }
188
189 return ret;
190}
191
192static int clk_sccg_pll2_find_setup(struct clk_sccg_pll_setup *setup,
193 struct clk_sccg_pll_setup *temp_setup,
194 uint64_t ref)
195{
196
197 int ret = -EINVAL;
79 198
80 if (!parent_rate) 199 if (ref < PLL_STAGE1_MIN_FREQ || ref > PLL_STAGE1_MAX_FREQ)
81 return 0; 200 return ret;
82 201
83 div = rate / (parent_rate * 2); 202 temp_setup->vco1 = ref;
84 203
85 return parent_rate * div * 2; 204 ret = clk_sccg_divr2_lookup(setup, temp_setup);
205 return ret;
86} 206}
87 207
88static int clk_pll1_set_rate(struct clk_hw *hw, unsigned long rate, 208static int clk_sccg_divf1_lookup(struct clk_sccg_pll_setup *setup,
89 unsigned long parent_rate) 209 struct clk_sccg_pll_setup *temp_setup)
90{ 210{
91 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 211 int ret = -EINVAL;
92 u32 val;
93 u32 divf;
94 212
95 if (!parent_rate) 213 for (temp_setup->divf1 = 0; temp_setup->divf1 <= PLL_DIVF1_MAX;
96 return -EINVAL; 214 temp_setup->divf1++) {
215 uint64_t vco1 = temp_setup->ref;
97 216
98 divf = rate / (parent_rate * 2); 217 do_div(vco1, temp_setup->divr1 + 1);
218 vco1 *= 2;
219 vco1 *= temp_setup->divf1 + 1;
99 220
100 val = readl_relaxed(pll->base + PLL_CFG2); 221 ret = clk_sccg_pll2_find_setup(setup, temp_setup, vco1);
101 val &= ~PLL_DIVF1_MASK; 222 if (!ret) {
102 val |= FIELD_PREP(PLL_DIVF1_MASK, divf - 1); 223 temp_setup->bypass = PLL_BYPASS_NONE;
103 writel_relaxed(val, pll->base + PLL_CFG2); 224 return ret;
225 }
226 }
227
228 return ret;
229}
230
231static int clk_sccg_divr1_lookup(struct clk_sccg_pll_setup *setup,
232 struct clk_sccg_pll_setup *temp_setup)
233{
234 int ret = -EINVAL;
235
236 for (temp_setup->divr1 = 0; temp_setup->divr1 <= PLL_DIVR1_MAX;
237 temp_setup->divr1++) {
238 temp_setup->ref_div1 = temp_setup->ref;
239 do_div(temp_setup->ref_div1, temp_setup->divr1 + 1);
240 if (temp_setup->ref_div1 >= PLL_STAGE1_REF_MIN_FREQ &&
241 temp_setup->ref_div1 <= PLL_STAGE1_REF_MAX_FREQ) {
242 ret = clk_sccg_divf1_lookup(setup, temp_setup);
243 if (!ret)
244 return ret;
245 }
246 }
247
248 return ret;
249}
250
251static int clk_sccg_pll1_find_setup(struct clk_sccg_pll_setup *setup,
252 struct clk_sccg_pll_setup *temp_setup,
253 uint64_t ref)
254{
255
256 int ret = -EINVAL;
257
258 if (ref < PLL_REF_MIN_FREQ || ref > PLL_REF_MAX_FREQ)
259 return ret;
260
261 temp_setup->ref = ref;
262
263 ret = clk_sccg_divr1_lookup(setup, temp_setup);
264
265 return ret;
266}
267
268static int clk_sccg_pll_find_setup(struct clk_sccg_pll_setup *setup,
269 uint64_t prate,
270 uint64_t rate, int try_bypass)
271{
272 struct clk_sccg_pll_setup temp_setup;
273 int ret = -EINVAL;
274
275 memset(&temp_setup, 0, sizeof(struct clk_sccg_pll_setup));
276 memset(setup, 0, sizeof(struct clk_sccg_pll_setup));
277
278 temp_setup.fout_error = PLL_OUT_MAX_FREQ;
279 temp_setup.fout_request = rate;
280
281 switch (try_bypass) {
104 282
105 return clk_pll_wait_lock(pll); 283 case PLL_BYPASS2:
284 if (prate == rate) {
285 setup->bypass = PLL_BYPASS2;
286 setup->fout = rate;
287 ret = 0;
288 }
289 break;
290
291 case PLL_BYPASS1:
292 ret = clk_sccg_pll2_find_setup(setup, &temp_setup, prate);
293 break;
294
295 case PLL_BYPASS_NONE:
296 ret = clk_sccg_pll1_find_setup(setup, &temp_setup, prate);
297 break;
298 }
299
300 return ret;
301}
302
303
304static int clk_sccg_pll_is_prepared(struct clk_hw *hw)
305{
306 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
307
308 u32 val = readl_relaxed(pll->base + PLL_CFG0);
309
310 return (val & PLL_PD_MASK) ? 0 : 1;
106} 311}
107 312
108static int clk_pll1_prepare(struct clk_hw *hw) 313static int clk_sccg_pll_prepare(struct clk_hw *hw)
109{ 314{
110 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 315 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
111 u32 val; 316 u32 val;
@@ -114,10 +319,10 @@ static int clk_pll1_prepare(struct clk_hw *hw)
114 val &= ~PLL_PD_MASK; 319 val &= ~PLL_PD_MASK;
115 writel_relaxed(val, pll->base + PLL_CFG0); 320 writel_relaxed(val, pll->base + PLL_CFG0);
116 321
117 return clk_pll_wait_lock(pll); 322 return clk_sccg_pll_wait_lock(pll);
118} 323}
119 324
120static void clk_pll1_unprepare(struct clk_hw *hw) 325static void clk_sccg_pll_unprepare(struct clk_hw *hw)
121{ 326{
122 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 327 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
123 u32 val; 328 u32 val;
@@ -125,121 +330,208 @@ static void clk_pll1_unprepare(struct clk_hw *hw)
125 val = readl_relaxed(pll->base + PLL_CFG0); 330 val = readl_relaxed(pll->base + PLL_CFG0);
126 val |= PLL_PD_MASK; 331 val |= PLL_PD_MASK;
127 writel_relaxed(val, pll->base + PLL_CFG0); 332 writel_relaxed(val, pll->base + PLL_CFG0);
128
129} 333}
130 334
131static unsigned long clk_pll2_recalc_rate(struct clk_hw *hw, 335static unsigned long clk_sccg_pll_recalc_rate(struct clk_hw *hw,
132 unsigned long parent_rate) 336 unsigned long parent_rate)
133{ 337{
134 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 338 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
135 u32 val, ref, divr1, divf1, divr2, divf2; 339 u32 val, divr1, divf1, divr2, divf2, divq;
136 u64 temp64; 340 u64 temp64;
137 341
138 val = readl_relaxed(pll->base + PLL_CFG0);
139 switch (FIELD_GET(PLL_REF_MASK, val)) {
140 case 0:
141 ref = OSC_25M;
142 break;
143 case 1:
144 ref = OSC_27M;
145 break;
146 default:
147 ref = OSC_25M;
148 break;
149 }
150
151 val = readl_relaxed(pll->base + PLL_CFG2); 342 val = readl_relaxed(pll->base + PLL_CFG2);
152 divr1 = FIELD_GET(PLL_DIVR1_MASK, val); 343 divr1 = FIELD_GET(PLL_DIVR1_MASK, val);
153 divr2 = FIELD_GET(PLL_DIVR2_MASK, val); 344 divr2 = FIELD_GET(PLL_DIVR2_MASK, val);
154 divf1 = FIELD_GET(PLL_DIVF1_MASK, val); 345 divf1 = FIELD_GET(PLL_DIVF1_MASK, val);
155 divf2 = FIELD_GET(PLL_DIVF2_MASK, val); 346 divf2 = FIELD_GET(PLL_DIVF2_MASK, val);
156 347 divq = FIELD_GET(PLL_DIVQ_MASK, val);
157 temp64 = ref * 2; 348
158 temp64 *= (divf1 + 1) * (divf2 + 1); 349 temp64 = parent_rate;
159 350
160 do_div(temp64, (divr1 + 1) * (divr2 + 1)); 351 val = clk_readl(pll->base + PLL_CFG0);
352 if (val & SSCG_PLL_BYPASS2_MASK) {
353 temp64 = parent_rate;
354 } else if (val & SSCG_PLL_BYPASS1_MASK) {
355 temp64 *= divf2;
356 do_div(temp64, (divr2 + 1) * (divq + 1));
357 } else {
358 temp64 *= 2;
359 temp64 *= (divf1 + 1) * (divf2 + 1);
360 do_div(temp64, (divr1 + 1) * (divr2 + 1) * (divq + 1));
361 }
161 362
162 return temp64; 363 return temp64;
163} 364}
164 365
165static long clk_pll2_round_rate(struct clk_hw *hw, unsigned long rate, 366static int clk_sccg_pll_set_rate(struct clk_hw *hw, unsigned long rate,
166 unsigned long *prate) 367 unsigned long parent_rate)
167{ 368{
168 u32 div; 369 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
169 unsigned long parent_rate = *prate; 370 struct clk_sccg_pll_setup *setup = &pll->setup;
371 u32 val;
170 372
171 if (!parent_rate) 373 /* set bypass here too since the parent might be the same */
172 return 0; 374 val = clk_readl(pll->base + PLL_CFG0);
375 val &= ~SSCG_PLL_BYPASS_MASK;
376 val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, setup->bypass);
377 clk_writel(val, pll->base + PLL_CFG0);
173 378
174 div = rate / parent_rate; 379 val = readl_relaxed(pll->base + PLL_CFG2);
380 val &= ~(PLL_DIVF1_MASK | PLL_DIVF2_MASK);
381 val &= ~(PLL_DIVR1_MASK | PLL_DIVR2_MASK | PLL_DIVQ_MASK);
382 val |= FIELD_PREP(PLL_DIVF1_MASK, setup->divf1);
383 val |= FIELD_PREP(PLL_DIVF2_MASK, setup->divf2);
384 val |= FIELD_PREP(PLL_DIVR1_MASK, setup->divr1);
385 val |= FIELD_PREP(PLL_DIVR2_MASK, setup->divr2);
386 val |= FIELD_PREP(PLL_DIVQ_MASK, setup->divq);
387 writel_relaxed(val, pll->base + PLL_CFG2);
175 388
176 return parent_rate * div; 389 return clk_sccg_pll_wait_lock(pll);
177} 390}
178 391
179static int clk_pll2_set_rate(struct clk_hw *hw, unsigned long rate, 392static u8 clk_sccg_pll_get_parent(struct clk_hw *hw)
180 unsigned long parent_rate)
181{ 393{
394 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
182 u32 val; 395 u32 val;
183 u32 divf; 396 u8 ret = pll->parent;
397
398 val = clk_readl(pll->base + PLL_CFG0);
399 if (val & SSCG_PLL_BYPASS2_MASK)
400 ret = pll->bypass2;
401 else if (val & SSCG_PLL_BYPASS1_MASK)
402 ret = pll->bypass1;
403 return ret;
404}
405
406static int clk_sccg_pll_set_parent(struct clk_hw *hw, u8 index)
407{
184 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw); 408 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
409 u32 val;
185 410
186 if (!parent_rate) 411 val = clk_readl(pll->base + PLL_CFG0);
187 return -EINVAL; 412 val &= ~SSCG_PLL_BYPASS_MASK;
413 val |= FIELD_PREP(SSCG_PLL_BYPASS_MASK, pll->setup.bypass);
414 clk_writel(val, pll->base + PLL_CFG0);
188 415
189 divf = rate / parent_rate; 416 return clk_sccg_pll_wait_lock(pll);
417}
190 418
191 val = readl_relaxed(pll->base + PLL_CFG2); 419static int __clk_sccg_pll_determine_rate(struct clk_hw *hw,
192 val &= ~PLL_DIVF2_MASK; 420 struct clk_rate_request *req,
193 val |= FIELD_PREP(PLL_DIVF2_MASK, divf - 1); 421 uint64_t min,
194 writel_relaxed(val, pll->base + PLL_CFG2); 422 uint64_t max,
423 uint64_t rate,
424 int bypass)
425{
426 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
427 struct clk_sccg_pll_setup *setup = &pll->setup;
428 struct clk_hw *parent_hw = NULL;
429 int bypass_parent_index;
430 int ret = -EINVAL;
431
432 req->max_rate = max;
433 req->min_rate = min;
434
435 switch (bypass) {
436 case PLL_BYPASS2:
437 bypass_parent_index = pll->bypass2;
438 break;
439 case PLL_BYPASS1:
440 bypass_parent_index = pll->bypass1;
441 break;
442 default:
443 bypass_parent_index = pll->parent;
444 break;
445 }
446
447 parent_hw = clk_hw_get_parent_by_index(hw, bypass_parent_index);
448 ret = __clk_determine_rate(parent_hw, req);
449 if (!ret) {
450 ret = clk_sccg_pll_find_setup(setup, req->rate,
451 rate, bypass);
452 }
453
454 req->best_parent_hw = parent_hw;
455 req->best_parent_rate = req->rate;
456 req->rate = setup->fout;
195 457
196 return clk_pll_wait_lock(pll); 458 return ret;
197} 459}
198 460
199static const struct clk_ops clk_sccg_pll1_ops = { 461static int clk_sccg_pll_determine_rate(struct clk_hw *hw,
200 .is_prepared = clk_pll1_is_prepared, 462 struct clk_rate_request *req)
201 .recalc_rate = clk_pll1_recalc_rate, 463{
202 .round_rate = clk_pll1_round_rate, 464 struct clk_sccg_pll *pll = to_clk_sccg_pll(hw);
203 .set_rate = clk_pll1_set_rate, 465 struct clk_sccg_pll_setup *setup = &pll->setup;
204}; 466 uint64_t rate = req->rate;
467 uint64_t min = req->min_rate;
468 uint64_t max = req->max_rate;
469 int ret = -EINVAL;
470
471 if (rate < PLL_OUT_MIN_FREQ || rate > PLL_OUT_MAX_FREQ)
472 return ret;
473
474 ret = __clk_sccg_pll_determine_rate(hw, req, req->rate, req->rate,
475 rate, PLL_BYPASS2);
476 if (!ret)
477 return ret;
478
479 ret = __clk_sccg_pll_determine_rate(hw, req, PLL_STAGE1_REF_MIN_FREQ,
480 PLL_STAGE1_REF_MAX_FREQ, rate,
481 PLL_BYPASS1);
482 if (!ret)
483 return ret;
484
485 ret = __clk_sccg_pll_determine_rate(hw, req, PLL_REF_MIN_FREQ,
486 PLL_REF_MAX_FREQ, rate,
487 PLL_BYPASS_NONE);
488 if (!ret)
489 return ret;
490
491 if (setup->fout >= min && setup->fout <= max)
492 ret = 0;
493
494 return ret;
495}
205 496
206static const struct clk_ops clk_sccg_pll2_ops = { 497static const struct clk_ops clk_sccg_pll_ops = {
207 .prepare = clk_pll1_prepare, 498 .prepare = clk_sccg_pll_prepare,
208 .unprepare = clk_pll1_unprepare, 499 .unprepare = clk_sccg_pll_unprepare,
209 .recalc_rate = clk_pll2_recalc_rate, 500 .is_prepared = clk_sccg_pll_is_prepared,
210 .round_rate = clk_pll2_round_rate, 501 .recalc_rate = clk_sccg_pll_recalc_rate,
211 .set_rate = clk_pll2_set_rate, 502 .set_rate = clk_sccg_pll_set_rate,
503 .set_parent = clk_sccg_pll_set_parent,
504 .get_parent = clk_sccg_pll_get_parent,
505 .determine_rate = clk_sccg_pll_determine_rate,
212}; 506};
213 507
214struct clk *imx_clk_sccg_pll(const char *name, 508struct clk *imx_clk_sccg_pll(const char *name,
215 const char *parent_name, 509 const char * const *parent_names,
510 u8 num_parents,
511 u8 parent, u8 bypass1, u8 bypass2,
216 void __iomem *base, 512 void __iomem *base,
217 enum imx_sccg_pll_type pll_type) 513 unsigned long flags)
218{ 514{
219 struct clk_sccg_pll *pll; 515 struct clk_sccg_pll *pll;
220 struct clk_init_data init; 516 struct clk_init_data init;
221 struct clk_hw *hw; 517 struct clk_hw *hw;
222 int ret; 518 int ret;
223 519
224 switch (pll_type) {
225 case SCCG_PLL1:
226 init.ops = &clk_sccg_pll1_ops;
227 break;
228 case SCCG_PLL2:
229 init.ops = &clk_sccg_pll2_ops;
230 break;
231 default:
232 return ERR_PTR(-EINVAL);
233 }
234
235 pll = kzalloc(sizeof(*pll), GFP_KERNEL); 520 pll = kzalloc(sizeof(*pll), GFP_KERNEL);
236 if (!pll) 521 if (!pll)
237 return ERR_PTR(-ENOMEM); 522 return ERR_PTR(-ENOMEM);
238 523
524 pll->parent = parent;
525 pll->bypass1 = bypass1;
526 pll->bypass2 = bypass2;
527
528 pll->base = base;
239 init.name = name; 529 init.name = name;
240 init.flags = 0; 530 init.ops = &clk_sccg_pll_ops;
241 init.parent_names = &parent_name; 531
242 init.num_parents = 1; 532 init.flags = flags;
533 init.parent_names = parent_names;
534 init.num_parents = num_parents;
243 535
244 pll->base = base; 536 pll->base = base;
245 pll->hw.init = &init; 537 pll->hw.init = &init;
diff --git a/drivers/clk/imx/clk.h b/drivers/clk/imx/clk.h
index 0aa48d3e3b95..5748ec8673e4 100644
--- a/drivers/clk/imx/clk.h
+++ b/drivers/clk/imx/clk.h
@@ -60,9 +60,12 @@ struct clk *imx_clk_pllv2(const char *name, const char *parent,
60struct clk *imx_clk_frac_pll(const char *name, const char *parent_name, 60struct clk *imx_clk_frac_pll(const char *name, const char *parent_name,
61 void __iomem *base); 61 void __iomem *base);
62 62
63struct clk *imx_clk_sccg_pll(const char *name, const char *parent_name, 63struct clk *imx_clk_sccg_pll(const char *name,
64 void __iomem *base, 64 const char * const *parent_names,
65 enum imx_sccg_pll_type pll_type); 65 u8 num_parents,
66 u8 parent, u8 bypass1, u8 bypass2,
67 void __iomem *base,
68 unsigned long flags);
66 69
67enum imx_pllv3_type { 70enum imx_pllv3_type {
68 IMX_PLLV3_GENERIC, 71 IMX_PLLV3_GENERIC,