1*83d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
2c4b45009SScott Branden /*
3c4b45009SScott Branden  * Copyright 2014 Broadcom Corporation.
4c4b45009SScott Branden  */
5c4b45009SScott Branden 
6c4b45009SScott Branden #include <common.h>
7c4b45009SScott Branden #include <asm/io.h>
8c4b45009SScott Branden #include <asm/iproc-common/armpll.h>
9c4b45009SScott Branden #include <asm/iproc-common/sysmap.h>
10c4b45009SScott Branden 
11c4b45009SScott Branden #define NELEMS(x)	(sizeof(x) / sizeof(x[0]))
12c4b45009SScott Branden 
13c4b45009SScott Branden struct armpll_parameters {
14c4b45009SScott Branden 	unsigned int mode;
15c4b45009SScott Branden 	unsigned int ndiv_int;
16c4b45009SScott Branden 	unsigned int ndiv_frac;
17c4b45009SScott Branden 	unsigned int pdiv;
18c4b45009SScott Branden 	unsigned int freqid;
19c4b45009SScott Branden };
20c4b45009SScott Branden 
21c4b45009SScott Branden struct armpll_parameters armpll_clk_tab[] = {
22c4b45009SScott Branden 	{   25, 64,      1, 1, 0},
23c4b45009SScott Branden 	{  100, 64,      1, 1, 2},
24c4b45009SScott Branden 	{  400, 64,      1, 1, 6},
25c4b45009SScott Branden 	{  448, 71, 713050, 1, 6},
26c4b45009SScott Branden 	{  500, 80,      1, 1, 6},
27c4b45009SScott Branden 	{  560, 89, 629145, 1, 6},
28c4b45009SScott Branden 	{  600, 96,      1, 1, 6},
29c4b45009SScott Branden 	{  800, 64,      1, 1, 7},
30c4b45009SScott Branden 	{  896, 71, 713050, 1, 7},
31c4b45009SScott Branden 	{ 1000, 80,      1, 1, 7},
32c4b45009SScott Branden 	{ 1100, 88,      1, 1, 7},
33c4b45009SScott Branden 	{ 1120, 89, 629145, 1, 7},
34c4b45009SScott Branden 	{ 1200, 96,      1, 1, 7},
35c4b45009SScott Branden };
36c4b45009SScott Branden 
armpll_config(uint32_t clkmhz)37c4b45009SScott Branden uint32_t armpll_config(uint32_t clkmhz)
38c4b45009SScott Branden {
39c4b45009SScott Branden 	uint32_t freqid;
40c4b45009SScott Branden 	uint32_t ndiv_frac;
41c4b45009SScott Branden 	uint32_t pll;
42c4b45009SScott Branden 	uint32_t status = 1;
43c4b45009SScott Branden 	uint32_t timeout_countdown;
44c4b45009SScott Branden 	int i;
45c4b45009SScott Branden 
46c4b45009SScott Branden 	for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
47c4b45009SScott Branden 		if (armpll_clk_tab[i].mode == clkmhz) {
48c4b45009SScott Branden 			status = 0;
49c4b45009SScott Branden 			break;
50c4b45009SScott Branden 		}
51c4b45009SScott Branden 	}
52c4b45009SScott Branden 
53c4b45009SScott Branden 	if (status) {
54c4b45009SScott Branden 		printf("Error: Clock configuration not supported\n");
55c4b45009SScott Branden 		goto armpll_config_done;
56c4b45009SScott Branden 	}
57c4b45009SScott Branden 
58c4b45009SScott Branden 	/* Enable write access */
59c4b45009SScott Branden 	writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
60c4b45009SScott Branden 
61c4b45009SScott Branden 	if (clkmhz == 25)
62c4b45009SScott Branden 		freqid = 0;
63c4b45009SScott Branden 	else
64c4b45009SScott Branden 		freqid = 2;
65c4b45009SScott Branden 
66c4b45009SScott Branden 	/* Bypass ARM clock and run on sysclk */
67c4b45009SScott Branden 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
68c4b45009SScott Branden 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
69c4b45009SScott Branden 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
70c4b45009SScott Branden 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
71c4b45009SScott Branden 	       freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
72c4b45009SScott Branden 	       IHOST_PROC_CLK_POLICY_FREQ);
73c4b45009SScott Branden 
74c4b45009SScott Branden 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
75c4b45009SScott Branden 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
76c4b45009SScott Branden 	       IHOST_PROC_CLK_POLICY_CTL);
77c4b45009SScott Branden 
78c4b45009SScott Branden 	/* Poll CCU until operation complete */
79c4b45009SScott Branden 	timeout_countdown = 0x100000;
80c4b45009SScott Branden 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
81c4b45009SScott Branden 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
82c4b45009SScott Branden 		timeout_countdown--;
83c4b45009SScott Branden 		if (timeout_countdown == 0) {
84c4b45009SScott Branden 			printf("CCU polling timedout\n");
85c4b45009SScott Branden 			status = 1;
86c4b45009SScott Branden 			goto armpll_config_done;
87c4b45009SScott Branden 		}
88c4b45009SScott Branden 	}
89c4b45009SScott Branden 
90c4b45009SScott Branden 	if (clkmhz == 25 || clkmhz == 100) {
91c4b45009SScott Branden 		status = 0;
92c4b45009SScott Branden 		goto armpll_config_done;
93c4b45009SScott Branden 	}
94c4b45009SScott Branden 
95c4b45009SScott Branden 	/* Now it is safe to program the PLL */
96c4b45009SScott Branden 	pll = readl(IHOST_PROC_CLK_PLLARMB);
97c4b45009SScott Branden 	pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
98c4b45009SScott Branden 	ndiv_frac =
99c4b45009SScott Branden 		((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
100c4b45009SScott Branden 		 (armpll_clk_tab[i].ndiv_frac <<
101c4b45009SScott Branden 		 IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
102c4b45009SScott Branden 	pll |= ndiv_frac;
103c4b45009SScott Branden 	writel(pll, IHOST_PROC_CLK_PLLARMB);
104c4b45009SScott Branden 
105c4b45009SScott Branden 	writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
106c4b45009SScott Branden 	       armpll_clk_tab[i].ndiv_int <<
107c4b45009SScott Branden 			IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
108c4b45009SScott Branden 	       armpll_clk_tab[i].pdiv <<
109c4b45009SScott Branden 			IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
110c4b45009SScott Branden 	       1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
111c4b45009SScott Branden 	       IHOST_PROC_CLK_PLLARMA);
112c4b45009SScott Branden 
113c4b45009SScott Branden 	/* Poll ARM PLL Lock until operation complete */
114c4b45009SScott Branden 	timeout_countdown = 0x100000;
115c4b45009SScott Branden 	while (readl(IHOST_PROC_CLK_PLLARMA) &
116c4b45009SScott Branden 	       (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
117c4b45009SScott Branden 		timeout_countdown--;
118c4b45009SScott Branden 		if (timeout_countdown == 0) {
119c4b45009SScott Branden 			printf("ARM PLL lock failed\n");
120c4b45009SScott Branden 			status = 1;
121c4b45009SScott Branden 			goto armpll_config_done;
122c4b45009SScott Branden 		}
123c4b45009SScott Branden 	}
124c4b45009SScott Branden 
125c4b45009SScott Branden 	pll = readl(IHOST_PROC_CLK_PLLARMA);
126c4b45009SScott Branden 	pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
127c4b45009SScott Branden 	writel(pll, IHOST_PROC_CLK_PLLARMA);
128c4b45009SScott Branden 
129c4b45009SScott Branden 	/* Set the policy */
130c4b45009SScott Branden 	writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
131c4b45009SScott Branden 	       armpll_clk_tab[i].freqid <<
132c4b45009SScott Branden 			IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
133c4b45009SScott Branden 	       armpll_clk_tab[i].freqid <<
134c4b45009SScott Branden 			IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
135c4b45009SScott Branden 	       armpll_clk_tab[i].freqid <<
136c4b45009SScott Branden 			IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
137c4b45009SScott Branden 	       armpll_clk_tab[i+4].freqid <<
138c4b45009SScott Branden 			IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
139c4b45009SScott Branden 	       IHOST_PROC_CLK_POLICY_FREQ);
140c4b45009SScott Branden 
141c4b45009SScott Branden 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
142c4b45009SScott Branden 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
143c4b45009SScott Branden 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
144c4b45009SScott Branden 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
145c4b45009SScott Branden 	writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
146c4b45009SScott Branden 
147c4b45009SScott Branden 	writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
148c4b45009SScott Branden 	       1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
149c4b45009SScott Branden 	       IHOST_PROC_CLK_POLICY_CTL);
150c4b45009SScott Branden 
151c4b45009SScott Branden 	/* Poll CCU until operation complete */
152c4b45009SScott Branden 	timeout_countdown = 0x100000;
153c4b45009SScott Branden 	while (readl(IHOST_PROC_CLK_POLICY_CTL) &
154c4b45009SScott Branden 	       (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
155c4b45009SScott Branden 		timeout_countdown--;
156c4b45009SScott Branden 		if (timeout_countdown == 0) {
157c4b45009SScott Branden 			printf("CCU polling failed\n");
158c4b45009SScott Branden 			status = 1;
159c4b45009SScott Branden 			goto armpll_config_done;
160c4b45009SScott Branden 		}
161c4b45009SScott Branden 	}
162c4b45009SScott Branden 
163c4b45009SScott Branden 	status = 0;
164c4b45009SScott Branden armpll_config_done:
165c4b45009SScott Branden 	/* Disable access to PLL registers */
166c4b45009SScott Branden 	writel(0, IHOST_PROC_CLK_WR_ACCESS);
167c4b45009SScott Branden 
168c4b45009SScott Branden 	return status;
169c4b45009SScott Branden }
170