]> git.sur5r.net Git - u-boot/blob - arch/arm/mach-uniphier/clk/pll-base-ld20.c
ARM: uniphier: compute SSCPLL values more precisely
[u-boot] / arch / arm / mach-uniphier / clk / pll-base-ld20.c
1 /*
2  * Copyright (C) 2016 Socionext Inc.
3  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4  *
5  * SPDX-License-Identifier:     GPL-2.0+
6  */
7
8 #include <linux/bitops.h>
9 #include <linux/delay.h>
10 #include <linux/kernel.h>
11 #include <linux/errno.h>
12 #include <linux/io.h>
13 #include <linux/sizes.h>
14
15 #include "pll.h"
16
17 /* PLL type: SSC */
18 #define SC_PLLCTRL_SSC_DK_MASK          GENMASK(14, 0)
19 #define SC_PLLCTRL_SSC_EN               BIT(31)
20 #define SC_PLLCTRL2_NRSTDS              BIT(28)
21 #define SC_PLLCTRL2_SSC_JK_MASK         GENMASK(26, 0)
22 #define SC_PLLCTRL3_REGI_SHIFT          16
23 #define SC_PLLCTRL3_REGI_MASK           GENMASK(19, 16)
24
25 /* PLL type: VPLL27 */
26 #define SC_VPLL27CTRL_WP                BIT(0)
27 #define SC_VPLL27CTRL3_K_LD             BIT(28)
28
29 /* PLL type: DSPLL */
30 #define SC_DSPLLCTRL2_K_LD              BIT(28)
31
32 int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
33                               unsigned int ssc_rate, unsigned int divn)
34 {
35         void __iomem *base;
36         u32 tmp;
37
38         base = ioremap(reg_base, SZ_16);
39         if (!base)
40                 return -ENOMEM;
41
42         if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
43                 tmp = readl(base);      /* SSCPLLCTRL */
44                 tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
45                 tmp |= DIV_ROUND_CLOSEST(487UL * freq * ssc_rate, divn * 512) &
46                                                         SC_PLLCTRL_SSC_DK_MASK;
47                 writel(tmp, base);
48
49                 tmp = readl(base + 4);
50                 tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
51                 tmp |= DIV_ROUND_CLOSEST(21431887UL * freq, divn * 512) &
52                                                         SC_PLLCTRL2_SSC_JK_MASK;
53                 writel(tmp, base + 4);
54
55                 udelay(50);
56         }
57
58         tmp = readl(base + 4);          /* SSCPLLCTRL2 */
59         tmp |= SC_PLLCTRL2_NRSTDS;
60         writel(tmp, base + 4);
61
62         iounmap(base);
63
64         return 0;
65 }
66
67 int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
68 {
69         void __iomem *base;
70         u32 tmp;
71
72         base = ioremap(reg_base, SZ_16);
73         if (!base)
74                 return -ENOMEM;
75
76         tmp = readl(base);      /* SSCPLLCTRL */
77         tmp |= SC_PLLCTRL_SSC_EN;
78         writel(tmp, base);
79
80         iounmap(base);
81
82         return 0;
83 }
84
85 int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi)
86 {
87         void __iomem *base;
88         u32 tmp;
89
90         base = ioremap(reg_base, SZ_16);
91         if (!base)
92                 return -ENOMEM;
93
94         tmp = readl(base + 8);  /* SSCPLLCTRL3 */
95         tmp &= ~SC_PLLCTRL3_REGI_MASK;
96         tmp |= regi << SC_PLLCTRL3_REGI_SHIFT;
97         writel(tmp, base + 8);
98
99         iounmap(base);
100
101         return 0;
102 }
103
104 int uniphier_ld20_vpll27_init(unsigned long reg_base)
105 {
106         void __iomem *base;
107         u32 tmp;
108
109         base = ioremap(reg_base, SZ_16);
110         if (!base)
111                 return -ENOMEM;
112
113         tmp = readl(base);              /* VPLL27CTRL */
114         tmp |= SC_VPLL27CTRL_WP;        /* write protect off */
115         writel(tmp, base);
116
117         tmp = readl(base + 8);          /* VPLL27CTRL3 */
118         tmp |= SC_VPLL27CTRL3_K_LD;
119         writel(tmp, base + 8);
120
121         tmp = readl(base);              /* VPLL27CTRL */
122         tmp &= ~SC_VPLL27CTRL_WP;       /* write protect on */
123         writel(tmp, base);
124
125         iounmap(base);
126
127         return 0;
128 }
129
130 int uniphier_ld20_dspll_init(unsigned long reg_base)
131 {
132         void __iomem *base;
133         u32 tmp;
134
135         base = ioremap(reg_base, SZ_16);
136         if (!base)
137                 return -ENOMEM;
138
139         tmp = readl(base + 4);          /* DSPLLCTRL2 */
140         tmp |= SC_DSPLLCTRL2_K_LD;
141         writel(tmp, base + 4);
142
143         iounmap(base);
144
145         return 0;
146 }