SPDX: Convert all of our single license tags to Linux Kernel style
[oweals/u-boot.git] / arch / arm / cpu / armv7 / iproc-common / armpll.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright 2014 Broadcom Corporation.
4  */
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
13 struct 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
21 struct armpll_parameters armpll_clk_tab[] = {
22         {   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 };
36
37 uint32_t armpll_config(uint32_t clkmhz)
38 {
39         uint32_t freqid;
40         uint32_t ndiv_frac;
41         uint32_t pll;
42         uint32_t status = 1;
43         uint32_t timeout_countdown;
44         int i;
45
46         for (i = 0; i < NELEMS(armpll_clk_tab); i++) {
47                 if (armpll_clk_tab[i].mode == clkmhz) {
48                         status = 0;
49                         break;
50                 }
51         }
52
53         if (status) {
54                 printf("Error: Clock configuration not supported\n");
55                 goto armpll_config_done;
56         }
57
58         /* Enable write access */
59         writel(IPROC_REG_WRITE_ACCESS, IHOST_PROC_CLK_WR_ACCESS);
60
61         if (clkmhz == 25)
62                 freqid = 0;
63         else
64                 freqid = 2;
65
66         /* Bypass ARM clock and run on sysclk */
67         writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
68                freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
69                freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
70                freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
71                freqid << IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
72                IHOST_PROC_CLK_POLICY_FREQ);
73
74         writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
75                1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
76                IHOST_PROC_CLK_POLICY_CTL);
77
78         /* Poll CCU until operation complete */
79         timeout_countdown = 0x100000;
80         while (readl(IHOST_PROC_CLK_POLICY_CTL) &
81                (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
82                 timeout_countdown--;
83                 if (timeout_countdown == 0) {
84                         printf("CCU polling timedout\n");
85                         status = 1;
86                         goto armpll_config_done;
87                 }
88         }
89
90         if (clkmhz == 25 || clkmhz == 100) {
91                 status = 0;
92                 goto armpll_config_done;
93         }
94
95         /* Now it is safe to program the PLL */
96         pll = readl(IHOST_PROC_CLK_PLLARMB);
97         pll &= ~((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1);
98         ndiv_frac =
99                 ((1 << IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_WIDTH) - 1) &
100                  (armpll_clk_tab[i].ndiv_frac <<
101                  IHOST_PROC_CLK_PLLARMB__PLLARM_NDIV_FRAC_R);
102         pll |= ndiv_frac;
103         writel(pll, IHOST_PROC_CLK_PLLARMB);
104
105         writel(1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK |
106                armpll_clk_tab[i].ndiv_int <<
107                         IHOST_PROC_CLK_PLLARMA__PLLARM_NDIV_INT_R |
108                armpll_clk_tab[i].pdiv <<
109                         IHOST_PROC_CLK_PLLARMA__PLLARM_PDIV_R |
110                1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_RESETB,
111                IHOST_PROC_CLK_PLLARMA);
112
113         /* Poll ARM PLL Lock until operation complete */
114         timeout_countdown = 0x100000;
115         while (readl(IHOST_PROC_CLK_PLLARMA) &
116                (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_LOCK)) {
117                 timeout_countdown--;
118                 if (timeout_countdown == 0) {
119                         printf("ARM PLL lock failed\n");
120                         status = 1;
121                         goto armpll_config_done;
122                 }
123         }
124
125         pll = readl(IHOST_PROC_CLK_PLLARMA);
126         pll |= (1 << IHOST_PROC_CLK_PLLARMA__PLLARM_SOFT_POST_RESETB);
127         writel(pll, IHOST_PROC_CLK_PLLARMA);
128
129         /* Set the policy */
130         writel(1 << IHOST_PROC_CLK_POLICY_FREQ__PRIV_ACCESS_MODE |
131                armpll_clk_tab[i].freqid <<
132                         IHOST_PROC_CLK_POLICY_FREQ__POLICY3_FREQ_R |
133                armpll_clk_tab[i].freqid <<
134                         IHOST_PROC_CLK_POLICY_FREQ__POLICY2_FREQ_R |
135                armpll_clk_tab[i].freqid <<
136                         IHOST_PROC_CLK_POLICY_FREQ__POLICY1_FREQ_R |
137                armpll_clk_tab[i+4].freqid <<
138                         IHOST_PROC_CLK_POLICY_FREQ__POLICY0_FREQ_R,
139                IHOST_PROC_CLK_POLICY_FREQ);
140
141         writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE0_CLKGATE);
142         writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_CORE1_CLKGATE);
143         writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_SWITCH_CLKGATE);
144         writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_ARM_PERIPH_CLKGATE);
145         writel(IPROC_CLKCT_HDELAY_SW_EN, IHOST_PROC_CLK_APB0_CLKGATE);
146
147         writel(1 << IHOST_PROC_CLK_POLICY_CTL__GO |
148                1 << IHOST_PROC_CLK_POLICY_CTL__GO_AC,
149                IHOST_PROC_CLK_POLICY_CTL);
150
151         /* Poll CCU until operation complete */
152         timeout_countdown = 0x100000;
153         while (readl(IHOST_PROC_CLK_POLICY_CTL) &
154                (1 << IHOST_PROC_CLK_POLICY_CTL__GO)) {
155                 timeout_countdown--;
156                 if (timeout_countdown == 0) {
157                         printf("CCU polling failed\n");
158                         status = 1;
159                         goto armpll_config_done;
160                 }
161         }
162
163         status = 0;
164 armpll_config_done:
165         /* Disable access to PLL registers */
166         writel(0, IHOST_PROC_CLK_WR_ACCESS);
167
168         return status;
169 }