1682e09ffSMasahiro Yamada /*
2682e09ffSMasahiro Yamada  * Copyright (C) 2016 Socionext Inc.
3682e09ffSMasahiro Yamada  *   Author: Masahiro Yamada <yamada.masahiro@socionext.com>
4682e09ffSMasahiro Yamada  *
5682e09ffSMasahiro Yamada  * SPDX-License-Identifier:	GPL-2.0+
6682e09ffSMasahiro Yamada  */
7682e09ffSMasahiro Yamada 
8682e09ffSMasahiro Yamada #include <linux/bitops.h>
9d9a70368SMasahiro Yamada #include <linux/delay.h>
10*f2ce50b2SMasahiro Yamada #include <linux/kernel.h>
11d9a70368SMasahiro Yamada #include <linux/errno.h>
12682e09ffSMasahiro Yamada #include <linux/io.h>
13682e09ffSMasahiro Yamada #include <linux/sizes.h>
14682e09ffSMasahiro Yamada 
15682e09ffSMasahiro Yamada #include "pll.h"
16682e09ffSMasahiro Yamada 
17682e09ffSMasahiro Yamada /* PLL type: SSC */
18682e09ffSMasahiro Yamada #define SC_PLLCTRL_SSC_DK_MASK		GENMASK(14, 0)
19682e09ffSMasahiro Yamada #define SC_PLLCTRL_SSC_EN		BIT(31)
20682e09ffSMasahiro Yamada #define SC_PLLCTRL2_NRSTDS		BIT(28)
21682e09ffSMasahiro Yamada #define SC_PLLCTRL2_SSC_JK_MASK		GENMASK(26, 0)
22bc647958SMasahiro Yamada #define SC_PLLCTRL3_REGI_SHIFT		16
23bc647958SMasahiro Yamada #define SC_PLLCTRL3_REGI_MASK		GENMASK(19, 16)
24682e09ffSMasahiro Yamada 
25682e09ffSMasahiro Yamada /* PLL type: VPLL27 */
26682e09ffSMasahiro Yamada #define SC_VPLL27CTRL_WP		BIT(0)
27682e09ffSMasahiro Yamada #define SC_VPLL27CTRL3_K_LD		BIT(28)
28682e09ffSMasahiro Yamada 
29682e09ffSMasahiro Yamada /* PLL type: DSPLL */
30682e09ffSMasahiro Yamada #define SC_DSPLLCTRL2_K_LD		BIT(28)
31682e09ffSMasahiro Yamada 
32682e09ffSMasahiro Yamada int uniphier_ld20_sscpll_init(unsigned long reg_base, unsigned int freq,
33682e09ffSMasahiro Yamada 			      unsigned int ssc_rate, unsigned int divn)
34682e09ffSMasahiro Yamada {
35682e09ffSMasahiro Yamada 	void __iomem *base;
36682e09ffSMasahiro Yamada 	u32 tmp;
37682e09ffSMasahiro Yamada 
38682e09ffSMasahiro Yamada 	base = ioremap(reg_base, SZ_16);
39682e09ffSMasahiro Yamada 	if (!base)
40682e09ffSMasahiro Yamada 		return -ENOMEM;
41682e09ffSMasahiro Yamada 
42682e09ffSMasahiro Yamada 	if (freq != UNIPHIER_PLL_FREQ_DEFAULT) {
43682e09ffSMasahiro Yamada 		tmp = readl(base);	/* SSCPLLCTRL */
44682e09ffSMasahiro Yamada 		tmp &= ~SC_PLLCTRL_SSC_DK_MASK;
45*f2ce50b2SMasahiro Yamada 		tmp |= DIV_ROUND_CLOSEST(487UL * freq * ssc_rate, divn * 512) &
46682e09ffSMasahiro Yamada 							SC_PLLCTRL_SSC_DK_MASK;
47682e09ffSMasahiro Yamada 		writel(tmp, base);
48682e09ffSMasahiro Yamada 
49682e09ffSMasahiro Yamada 		tmp = readl(base + 4);
50682e09ffSMasahiro Yamada 		tmp &= ~SC_PLLCTRL2_SSC_JK_MASK;
51*f2ce50b2SMasahiro Yamada 		tmp |= DIV_ROUND_CLOSEST(21431887UL * freq, divn * 512) &
52*f2ce50b2SMasahiro Yamada 							SC_PLLCTRL2_SSC_JK_MASK;
53c30c44e7SDai Okamura 		writel(tmp, base + 4);
54682e09ffSMasahiro Yamada 
55682e09ffSMasahiro Yamada 		udelay(50);
56682e09ffSMasahiro Yamada 	}
57682e09ffSMasahiro Yamada 
58682e09ffSMasahiro Yamada 	tmp = readl(base + 4);		/* SSCPLLCTRL2 */
59682e09ffSMasahiro Yamada 	tmp |= SC_PLLCTRL2_NRSTDS;
60682e09ffSMasahiro Yamada 	writel(tmp, base + 4);
61682e09ffSMasahiro Yamada 
62682e09ffSMasahiro Yamada 	iounmap(base);
63682e09ffSMasahiro Yamada 
64682e09ffSMasahiro Yamada 	return 0;
65682e09ffSMasahiro Yamada }
66682e09ffSMasahiro Yamada 
67682e09ffSMasahiro Yamada int uniphier_ld20_sscpll_ssc_en(unsigned long reg_base)
68682e09ffSMasahiro Yamada {
69682e09ffSMasahiro Yamada 	void __iomem *base;
70682e09ffSMasahiro Yamada 	u32 tmp;
71682e09ffSMasahiro Yamada 
72682e09ffSMasahiro Yamada 	base = ioremap(reg_base, SZ_16);
73682e09ffSMasahiro Yamada 	if (!base)
74682e09ffSMasahiro Yamada 		return -ENOMEM;
75682e09ffSMasahiro Yamada 
76682e09ffSMasahiro Yamada 	tmp = readl(base);	/* SSCPLLCTRL */
77682e09ffSMasahiro Yamada 	tmp |= SC_PLLCTRL_SSC_EN;
78682e09ffSMasahiro Yamada 	writel(tmp, base);
79682e09ffSMasahiro Yamada 
80682e09ffSMasahiro Yamada 	iounmap(base);
81682e09ffSMasahiro Yamada 
82682e09ffSMasahiro Yamada 	return 0;
83682e09ffSMasahiro Yamada }
84682e09ffSMasahiro Yamada 
85bc647958SMasahiro Yamada int uniphier_ld20_sscpll_set_regi(unsigned long reg_base, unsigned regi)
86bc647958SMasahiro Yamada {
87bc647958SMasahiro Yamada 	void __iomem *base;
88bc647958SMasahiro Yamada 	u32 tmp;
89bc647958SMasahiro Yamada 
90bc647958SMasahiro Yamada 	base = ioremap(reg_base, SZ_16);
91bc647958SMasahiro Yamada 	if (!base)
92bc647958SMasahiro Yamada 		return -ENOMEM;
93bc647958SMasahiro Yamada 
944013bbb1SDai Okamura 	tmp = readl(base + 8);	/* SSCPLLCTRL3 */
95bc647958SMasahiro Yamada 	tmp &= ~SC_PLLCTRL3_REGI_MASK;
96bc647958SMasahiro Yamada 	tmp |= regi << SC_PLLCTRL3_REGI_SHIFT;
97bc647958SMasahiro Yamada 	writel(tmp, base + 8);
98bc647958SMasahiro Yamada 
99bc647958SMasahiro Yamada 	iounmap(base);
100bc647958SMasahiro Yamada 
101bc647958SMasahiro Yamada 	return 0;
102bc647958SMasahiro Yamada }
103bc647958SMasahiro Yamada 
104682e09ffSMasahiro Yamada int uniphier_ld20_vpll27_init(unsigned long reg_base)
105682e09ffSMasahiro Yamada {
106682e09ffSMasahiro Yamada 	void __iomem *base;
107682e09ffSMasahiro Yamada 	u32 tmp;
108682e09ffSMasahiro Yamada 
109682e09ffSMasahiro Yamada 	base = ioremap(reg_base, SZ_16);
110682e09ffSMasahiro Yamada 	if (!base)
111682e09ffSMasahiro Yamada 		return -ENOMEM;
112682e09ffSMasahiro Yamada 
113682e09ffSMasahiro Yamada 	tmp = readl(base);		/* VPLL27CTRL */
114682e09ffSMasahiro Yamada 	tmp |= SC_VPLL27CTRL_WP;	/* write protect off */
115682e09ffSMasahiro Yamada 	writel(tmp, base);
116682e09ffSMasahiro Yamada 
117682e09ffSMasahiro Yamada 	tmp = readl(base + 8);		/* VPLL27CTRL3 */
118682e09ffSMasahiro Yamada 	tmp |= SC_VPLL27CTRL3_K_LD;
119682e09ffSMasahiro Yamada 	writel(tmp, base + 8);
120682e09ffSMasahiro Yamada 
121682e09ffSMasahiro Yamada 	tmp = readl(base);		/* VPLL27CTRL */
122682e09ffSMasahiro Yamada 	tmp &= ~SC_VPLL27CTRL_WP;	/* write protect on */
123682e09ffSMasahiro Yamada 	writel(tmp, base);
124682e09ffSMasahiro Yamada 
125682e09ffSMasahiro Yamada 	iounmap(base);
126682e09ffSMasahiro Yamada 
127682e09ffSMasahiro Yamada 	return 0;
128682e09ffSMasahiro Yamada }
129682e09ffSMasahiro Yamada 
130682e09ffSMasahiro Yamada int uniphier_ld20_dspll_init(unsigned long reg_base)
131682e09ffSMasahiro Yamada {
132682e09ffSMasahiro Yamada 	void __iomem *base;
133682e09ffSMasahiro Yamada 	u32 tmp;
134682e09ffSMasahiro Yamada 
135682e09ffSMasahiro Yamada 	base = ioremap(reg_base, SZ_16);
136682e09ffSMasahiro Yamada 	if (!base)
137682e09ffSMasahiro Yamada 		return -ENOMEM;
138682e09ffSMasahiro Yamada 
1394013bbb1SDai Okamura 	tmp = readl(base + 4);		/* DSPLLCTRL2 */
140682e09ffSMasahiro Yamada 	tmp |= SC_DSPLLCTRL2_K_LD;
1414013bbb1SDai Okamura 	writel(tmp, base + 4);
142682e09ffSMasahiro Yamada 
143682e09ffSMasahiro Yamada 	iounmap(base);
144682e09ffSMasahiro Yamada 
145682e09ffSMasahiro Yamada 	return 0;
146682e09ffSMasahiro Yamada }
147