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