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