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