blob: a3a41c739b0c00e17a8b647f9b7f6b811b035e11 [file] [log] [blame]
Patrick Georgiac959032020-05-05 22:49:26 +02001 /* SPDX-License-Identifier: GPL-2.0-only */
Pranav Agrawale651e012018-11-20 18:16:26 +05302
Patrick Georgic3239632019-04-23 21:31:24 +02003#include <console/console.h>
Pranav Agrawale651e012018-11-20 18:16:26 +05304#include <device/mmio.h>
5#include <types.h>
Pranav Agrawale651e012018-11-20 18:16:26 +05306#include <commonlib/helpers.h>
Pranav Agrawale651e012018-11-20 18:16:26 +05307#include <soc/clock.h>
8
9#define DIV(div) (div ? (2*div - 1) : 0)
10#define HALF_DIVIDER(div2x) (div2x ? (div2x - 1) : 0)
11
12struct clock_config uart_cfg[] = {
13 {
14 .hz = 1843200,
15 .hw_ctl = 0x0,
16 .src = SRC_GPLL0_MAIN_800MHZ,
17 .div = DIV(0),
18 .m = 36,
19 .n = 15625,
20 .d_2 = 15625,
21 },
22 {
23 .hz = 3686400,
24 .hw_ctl = 0x0,
25 .src = SRC_GPLL0_MAIN_800MHZ,
26 .div = DIV(0),
27 .m = 72,
28 .n = 15625,
29 .d_2 = 15625,
30 }
31};
32
33struct clock_config i2c_cfg[] = {
34 {
35 .hz = 19200000,
36 .hw_ctl = 0x0,
37 .src = SRC_XO_19_2MHZ,
38 .div = DIV(0),
39 },
40 {
41 .hz = 50000000,
42 .hw_ctl = 0x0,
43 .src = SRC_GPLL0_MAIN_800MHZ,
44 .div = DIV(32),
45 }
46};
47
48struct clock_config spi_cfg[] = {
49 {
50 .hz = 1000000,
51 .hw_ctl = 0x0,
52 .src = SRC_XO_19_2MHZ,
53 .div = DIV(48),
54 },
55 {
56 .hz = 7372800,
57 .src = SRC_GPLL0_MAIN_800MHZ,
58 .div = DIV(1),
59 .m = 144,
60 .n = 15625,
61 .d_2 = 15625,
62 },
63 {
64 .hz = 19200000,
65 .hw_ctl = 0x0,
66 .src = SRC_XO_19_2MHZ,
67 .div = DIV(0),
68 },
69 {
70 .hz = 30000000,
71 .hw_ctl = 0x0,
72 .src = SRC_XO_19_2MHZ,
73 .div = DIV(0),
74 },
75 {
76 .hz = 50000000,
77 .hw_ctl = 0x0,
78 .src = SRC_GPLL0_MAIN_800MHZ,
79 .div = DIV(32),
80 }
81};
82
83static int clock_configure_gpll0(void)
84{
85 /* Keep existing GPLL0 configuration, in RUN mode @800Mhz. */
Julius Werner55009af2019-12-02 22:03:27 -080086 setbits32(&gcc->gpll0.user_ctl,
Pranav Agrawale651e012018-11-20 18:16:26 +053087 1 << CLK_CTL_GPLL_PLLOUT_LV_EARLY_SHFT |
88 1 << CLK_CTL_GPLL_PLLOUT_AUX2_SHFT |
89 1 << CLK_CTL_GPLL_PLLOUT_AUX_SHFT |
90 1 << CLK_CTL_GPLL_PLLOUT_MAIN_SHFT);
91 return 0;
92}
93
94static int clock_configure_mnd(struct qcs405_clock *clk, uint32_t m, uint32_t n,
95 uint32_t d_2)
96{
97 uint32_t reg_val;
98
99 /* Configure Root Clock Generator(RCG) for Dual Edge Mode */
100 reg_val = read32(&clk->rcg.cfg);
101 reg_val |= (2 << CLK_CTL_CFG_MODE_SHFT);
102 write32(&clk->rcg.cfg, reg_val);
103
104 /* Set M/N/D config */
105 write32(&clk->m, m & CLK_CTL_RCG_MND_BMSK);
106 write32(&clk->n, ~(n-m) & CLK_CTL_RCG_MND_BMSK);
107 write32(&clk->d_2, ~(d_2) & CLK_CTL_RCG_MND_BMSK);
108
109 return 0;
110}
111
112static int clock_configure(struct qcs405_clock *clk,
113 struct clock_config *clk_cfg,
114 uint32_t hz, uint32_t num_perfs)
115{
116 uint32_t reg_val;
117 uint32_t idx;
118
119 for (idx = 0; idx < num_perfs; idx++)
120 if (hz <= clk_cfg[idx].hz)
121 break;
122
123 reg_val = (clk_cfg[idx].src << CLK_CTL_CFG_SRC_SEL_SHFT) |
124 (clk_cfg[idx].div << CLK_CTL_CFG_SRC_DIV_SHFT);
125
126 /* Set clock config */
127 write32(&clk->rcg.cfg, reg_val);
128
129 if (clk_cfg[idx].m != 0)
130 clock_configure_mnd(clk, clk_cfg[idx].m, clk_cfg[idx].n,
131 clk_cfg[idx].d_2);
132
133 /* Commit config to RCG*/
Julius Werner55009af2019-12-02 22:03:27 -0800134 setbits32(&clk->rcg.cmd, BIT(CLK_CTL_CMD_UPDATE_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530135
136 return 0;
137}
138
139static bool clock_is_off(void *cbcr_addr)
140{
141 return (read32(cbcr_addr) & CLK_CTL_CBC_CLK_OFF_BMSK);
142}
143
144static int clock_enable_vote(void *cbcr_addr, void *vote_addr,
145 uint32_t vote_bit)
146{
Pranav Agrawale651e012018-11-20 18:16:26 +0530147 /* Set clock vote bit */
Julius Werner55009af2019-12-02 22:03:27 -0800148 setbits32(vote_addr, BIT(vote_bit));
Pranav Agrawale651e012018-11-20 18:16:26 +0530149
150 /* Ensure clock is enabled */
151 while (clock_is_off(cbcr_addr));
152
153 return 0;
154}
155
156static int clock_enable(void *cbcr_addr)
157{
Pranav Agrawale651e012018-11-20 18:16:26 +0530158 /* Set clock enable bit */
Julius Werner55009af2019-12-02 22:03:27 -0800159 setbits32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530160
161 /* Ensure clock is enabled */
162 while (clock_is_off(cbcr_addr))
163 ;
164
165 return 0;
166}
167
168static int clock_disable(void *cbcr_addr)
169{
Pranav Agrawale651e012018-11-20 18:16:26 +0530170 /* Set clock enable bit */
Julius Werner55009af2019-12-02 22:03:27 -0800171 clrbits32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530172 return 0;
173}
174
175int clock_reset_bcr(void *bcr_addr, bool reset)
176{
177 struct qcs405_bcr *bcr = bcr_addr;
178
179 if (reset)
Julius Werner55009af2019-12-02 22:03:27 -0800180 setbits32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530181 else
Julius Werner55009af2019-12-02 22:03:27 -0800182 clrbits32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530183
184 return 0;
185}
186
187void clock_configure_uart(uint32_t hz)
188{
189 struct qcs405_clock *uart_clk = (struct qcs405_clock *)
190 &gcc->blsp1_uart2_apps_clk;
191
192 clock_configure(uart_clk, uart_cfg, hz, ARRAY_SIZE(uart_cfg));
193}
194
Taniya Das3ee48572019-03-28 16:54:15 +0530195void clock_configure_spi(int blsp, int qup, uint32_t hz)
Pranav Agrawale651e012018-11-20 18:16:26 +0530196{
Taniya Das3ee48572019-03-28 16:54:15 +0530197 struct qcs405_clock *spi_clk = 0;
198
199 if (blsp == 1) {
200 switch (qup) {
201 case 0:
202 spi_clk = (struct qcs405_clock *)
203 &gcc->blsp1_qup0_spi_clk;
204 break;
205 case 1:
206 spi_clk = (struct qcs405_clock *)
207 &gcc->blsp1_qup1_spi_clk;
208 break;
209 case 2:
210 spi_clk = (struct qcs405_clock *)
211 &gcc->blsp1_qup2_spi_clk;
212 break;
213 case 3:
214 spi_clk = (struct qcs405_clock *)
215 &gcc->blsp1_qup3_spi_clk;
216 break;
217 case 4:
218 spi_clk = (struct qcs405_clock *)
219 &gcc->blsp1_qup4_spi_clk;
220 break;
Jacob Garber53b4b282019-07-23 11:46:24 -0600221 default:
222 printk(BIOS_ERR, "Invalid QUP %d\n", qup);
223 return;
Taniya Das3ee48572019-03-28 16:54:15 +0530224 }
Jacob Garber53b4b282019-07-23 11:46:24 -0600225 } else if (blsp == 2) {
Taniya Das3ee48572019-03-28 16:54:15 +0530226 spi_clk = (struct qcs405_clock *)&gcc->blsp2_qup0_spi_clk;
Jacob Garber53b4b282019-07-23 11:46:24 -0600227 } else {
228 printk(BIOS_ERR, "BLSP %d not supported\n", blsp);
229 return;
230 }
Pranav Agrawale651e012018-11-20 18:16:26 +0530231
232 clock_configure(spi_clk, spi_cfg, hz, ARRAY_SIZE(spi_cfg));
233}
234
Taniya Das846f8c02019-04-17 15:58:15 +0530235void clock_configure_i2c(uint32_t hz)
236{
237 struct qcs405_clock *i2c_clk =
238 (struct qcs405_clock *)&gcc->blsp1_qup1_i2c_clk;
239
240 clock_configure(i2c_clk, i2c_cfg, hz, ARRAY_SIZE(i2c_cfg));
241}
242
Pranav Agrawale651e012018-11-20 18:16:26 +0530243void clock_enable_uart(void)
244{
245 clock_enable(&gcc->blsp1_uart2_apps_cbcr);
246}
247
248void clock_disable_uart(void)
249{
250 clock_disable(&gcc->blsp1_uart2_apps_cbcr);
251}
252
Taniya Das3ee48572019-03-28 16:54:15 +0530253void clock_enable_spi(int blsp, int qup)
Pranav Agrawale651e012018-11-20 18:16:26 +0530254{
Taniya Das3ee48572019-03-28 16:54:15 +0530255 if (blsp == 1) {
256 switch (qup) {
257 case 0:
258 clock_enable(&gcc->blsp1_qup0_spi_apps_cbcr);
259 break;
260 case 1:
261 clock_enable(&gcc->blsp1_qup1_spi_apps_cbcr);
262 break;
263 case 2:
264 clock_enable(&gcc->blsp1_qup2_spi_apps_cbcr);
265 break;
266 case 3:
267 clock_enable(&gcc->blsp1_qup3_spi_apps_cbcr);
268 break;
269 case 4:
270 clock_enable(&gcc->blsp1_qup4_spi_apps_cbcr);
271 break;
272 }
273 } else if (blsp == 2)
274 clock_enable(&gcc->blsp2_qup0_spi_apps_cbcr);
275 else
276 printk(BIOS_ERR, "BLSP%d not supported\n", blsp);
Pranav Agrawale651e012018-11-20 18:16:26 +0530277}
278
Taniya Das3ee48572019-03-28 16:54:15 +0530279void clock_disable_spi(int blsp, int qup)
Pranav Agrawale651e012018-11-20 18:16:26 +0530280{
Taniya Das3ee48572019-03-28 16:54:15 +0530281 if (blsp == 1) {
282 switch (qup) {
283 case 0:
284 clock_enable(&gcc->blsp1_qup0_spi_apps_cbcr);
285 break;
286 case 1:
287 clock_enable(&gcc->blsp1_qup1_spi_apps_cbcr);
288 break;
289 case 2:
290 clock_enable(&gcc->blsp1_qup2_spi_apps_cbcr);
291 break;
292 case 3:
293 clock_enable(&gcc->blsp1_qup3_spi_apps_cbcr);
294 break;
295 case 4:
296 clock_enable(&gcc->blsp1_qup4_spi_apps_cbcr);
297 break;
298 }
299 } else if (blsp == 2)
300 clock_enable(&gcc->blsp2_qup0_spi_apps_cbcr);
301 else
302 printk(BIOS_ERR, "BLSP%d not supported\n", blsp);
Pranav Agrawale651e012018-11-20 18:16:26 +0530303}
304
Taniya Das846f8c02019-04-17 15:58:15 +0530305void clock_enable_i2c(void)
306{
307 clock_enable(&gcc->blsp1_qup1_i2c_apps_cbcr);
308}
309
310void clock_disable_i2c(void)
311{
312 clock_disable(&gcc->blsp1_qup1_i2c_apps_cbcr);
313}
314
Pranav Agrawale651e012018-11-20 18:16:26 +0530315void clock_init(void)
316{
Pranav Agrawale651e012018-11-20 18:16:26 +0530317 clock_configure_gpll0();
Pranav Agrawale651e012018-11-20 18:16:26 +0530318 clock_enable_vote(&gcc->blsp1_ahb_cbcr,
319 &gcc->gcc_apcs_clock_branch_en_vote,
320 BLSP1_AHB_CLK_ENA);
321
Pranav Agrawale651e012018-11-20 18:16:26 +0530322 clock_enable_vote(&gcc->blsp2_ahb_cbcr,
323 &gcc->gcc_apcs_clock_branch_en_vote,
324 BLSP2_AHB_CLK_ENA);
325}