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