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/errno.h>
11 #include <linux/io.h>
12 #include <linux/sizes.h>
13 
14 #include "pll.h"
15 
16 /* PLL type: SSC */
17 #define SC_PLLCTRL_SSC_DK_MASK		GENMASK(14, 0)
18 #define SC_PLLCTRL_SSC_EN		BIT(31)
19 #define SC_PLLCTRL2_NRSTDS		BIT(28)
20 #define SC_PLLCTRL2_SSC_JK_MASK		GENMASK(26, 0)
21 #define SC_PLLCTRL3_REGI_SHIFT		16
22 #define SC_PLLCTRL3_REGI_MASK		GENMASK(19, 16)
23 
24 /* PLL type: VPLL27 */
25 #define SC_VPLL27CTRL_WP		BIT(0)
26 #define SC_VPLL27CTRL3_K_LD		BIT(28)
27 
28 /* PLL type: DSPLL */
29 #define SC_DSPLLCTRL2_K_LD		BIT(28)
30 
31 int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
32 			      unsigned int ssc_rate, unsigned int divn)
33 {
34 	void __iomem *base;
35 	u32 tmp;
36 
37 	base = ioremap(reg_base, SZ_16);
38 	if (!base)
39 		return -ENOMEM;
40 
41 	if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
42 		tmp = readl(base);	/* SSCPLLCTRL */
43 		tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
44 		tmp |= (487 * freq * ssc_rate / divn / 512) &
45 							SC_PLLCTRL_SSC_DK_MASK;
46 		writel(tmp, base);
47 
48 		tmp = readl(base + 4);
49 		tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
50 		tmp |= (41859 * freq / divn) & SC_PLLCTRL2_SSC_JK_MASK;
51 		writel(tmp, base + 4);
52 
53 		udelay(50);
54 	}
55 
56 	tmp = readl(base + 4);		/* SSCPLLCTRL2 */
57 	tmp |= SC_PLLCTRL2_NRSTDS;
58 	writel(tmp, base + 4);
59 
60 	iounmap(base);
61 
62 	return 0;
63 }
64 
65 int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
66 {
67 	void __iomem *base;
68 	u32 tmp;
69 
70 	base = ioremap(reg_base, SZ_16);
71 	if (!base)
72 		return -ENOMEM;
73 
74 	tmp = readl(base);	/* SSCPLLCTRL */
75 	tmp |= SC_PLLCTRL_SSC_EN;
76 	writel(tmp, base);
77 
78 	iounmap(base);
79 
80 	return 0;
81 }
82 
83 int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi)
84 {
85 	void __iomem *base;
86 	u32 tmp;
87 
88 	base = ioremap(reg_base, SZ_16);
89 	if (!base)
90 		return -ENOMEM;
91 
92 	tmp = readl(base + 8);	/* SSCPLLCTRL3 */
93 	tmp &= ~SC_PLLCTRL3_REGI_MASK;
94 	tmp |= regi << SC_PLLCTRL3_REGI_SHIFT;
95 	writel(tmp, base + 8);
96 
97 	iounmap(base);
98 
99 	return 0;
100 }
101 
102 int uniphier_ld20_vpll27_init(unsigned long reg_base)
103 {
104 	void __iomem *base;
105 	u32 tmp;
106 
107 	base = ioremap(reg_base, SZ_16);
108 	if (!base)
109 		return -ENOMEM;
110 
111 	tmp = readl(base);		/* VPLL27CTRL */
112 	tmp |= SC_VPLL27CTRL_WP;	/* write protect off */
113 	writel(tmp, base);
114 
115 	tmp = readl(base + 8);		/* VPLL27CTRL3 */
116 	tmp |= SC_VPLL27CTRL3_K_LD;
117 	writel(tmp, base + 8);
118 
119 	tmp = readl(base);		/* VPLL27CTRL */
120 	tmp &= ~SC_VPLL27CTRL_WP;	/* write protect on */
121 	writel(tmp, base);
122 
123 	iounmap(base);
124 
125 	return 0;
126 }
127 
128 int uniphier_ld20_dspll_init(unsigned long reg_base)
129 {
130 	void __iomem *base;
131 	u32 tmp;
132 
133 	base = ioremap(reg_base, SZ_16);
134 	if (!base)
135 		return -ENOMEM;
136 
137 	tmp = readl(base + 4);		/* DSPLLCTRL2 */
138 	tmp |= SC_DSPLLCTRL2_K_LD;
139 	writel(tmp, base + 4);
140 
141 	iounmap(base);
142 
143 	return 0;
144 }
145