blob: ce846543dc59ea27eb382faa219f76d09430cd18 [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{
147
148 /* Set clock vote bit */
Julius Werner55009af2019-12-02 22:03:27 -0800149 setbits32(vote_addr, BIT(vote_bit));
Pranav Agrawale651e012018-11-20 18:16:26 +0530150
151 /* Ensure clock is enabled */
152 while (clock_is_off(cbcr_addr));
153
154 return 0;
155}
156
157static int clock_enable(void *cbcr_addr)
158{
159
160 /* Set clock enable bit */
Julius Werner55009af2019-12-02 22:03:27 -0800161 setbits32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530162
163 /* Ensure clock is enabled */
164 while (clock_is_off(cbcr_addr))
165 ;
166
167 return 0;
168}
169
170static int clock_disable(void *cbcr_addr)
171{
172
173 /* Set clock enable bit */
Julius Werner55009af2019-12-02 22:03:27 -0800174 clrbits32(cbcr_addr, BIT(CLK_CTL_CBC_CLK_EN_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530175 return 0;
176}
177
178int clock_reset_bcr(void *bcr_addr, bool reset)
179{
180 struct qcs405_bcr *bcr = bcr_addr;
181
182 if (reset)
Julius Werner55009af2019-12-02 22:03:27 -0800183 setbits32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530184 else
Julius Werner55009af2019-12-02 22:03:27 -0800185 clrbits32(&bcr->bcr, BIT(CLK_CTL_BCR_BLK_ARES_SHFT));
Pranav Agrawale651e012018-11-20 18:16:26 +0530186
187 return 0;
188}
189
190void clock_configure_uart(uint32_t hz)
191{
192 struct qcs405_clock *uart_clk = (struct qcs405_clock *)
193 &gcc->blsp1_uart2_apps_clk;
194
195 clock_configure(uart_clk, uart_cfg, hz, ARRAY_SIZE(uart_cfg));
196}
197
Taniya Das3ee48572019-03-28 16:54:15 +0530198void clock_configure_spi(int blsp, int qup, uint32_t hz)
Pranav Agrawale651e012018-11-20 18:16:26 +0530199{
Taniya Das3ee48572019-03-28 16:54:15 +0530200 struct qcs405_clock *spi_clk = 0;
201
202 if (blsp == 1) {
203 switch (qup) {
204 case 0:
205 spi_clk = (struct qcs405_clock *)
206 &gcc->blsp1_qup0_spi_clk;
207 break;
208 case 1:
209 spi_clk = (struct qcs405_clock *)
210 &gcc->blsp1_qup1_spi_clk;
211 break;
212 case 2:
213 spi_clk = (struct qcs405_clock *)
214 &gcc->blsp1_qup2_spi_clk;
215 break;
216 case 3:
217 spi_clk = (struct qcs405_clock *)
218 &gcc->blsp1_qup3_spi_clk;
219 break;
220 case 4:
221 spi_clk = (struct qcs405_clock *)
222 &gcc->blsp1_qup4_spi_clk;
223 break;
Jacob Garber53b4b282019-07-23 11:46:24 -0600224 default:
225 printk(BIOS_ERR, "Invalid QUP %d\n", qup);
226 return;
Taniya Das3ee48572019-03-28 16:54:15 +0530227 }
Jacob Garber53b4b282019-07-23 11:46:24 -0600228 } else if (blsp == 2) {
Taniya Das3ee48572019-03-28 16:54:15 +0530229 spi_clk = (struct qcs405_clock *)&gcc->blsp2_qup0_spi_clk;
Jacob Garber53b4b282019-07-23 11:46:24 -0600230 } else {
231 printk(BIOS_ERR, "BLSP %d not supported\n", blsp);
232 return;
233 }
Pranav Agrawale651e012018-11-20 18:16:26 +0530234
235 clock_configure(spi_clk, spi_cfg, hz, ARRAY_SIZE(spi_cfg));
236}
237
Taniya Das846f8c02019-04-17 15:58:15 +0530238void clock_configure_i2c(uint32_t hz)
239{
240 struct qcs405_clock *i2c_clk =
241 (struct qcs405_clock *)&gcc->blsp1_qup1_i2c_clk;
242
243 clock_configure(i2c_clk, i2c_cfg, hz, ARRAY_SIZE(i2c_cfg));
244}
245
Pranav Agrawale651e012018-11-20 18:16:26 +0530246void clock_enable_uart(void)
247{
248 clock_enable(&gcc->blsp1_uart2_apps_cbcr);
249}
250
251void clock_disable_uart(void)
252{
253 clock_disable(&gcc->blsp1_uart2_apps_cbcr);
254}
255
Taniya Das3ee48572019-03-28 16:54:15 +0530256void clock_enable_spi(int blsp, int qup)
Pranav Agrawale651e012018-11-20 18:16:26 +0530257{
Taniya Das3ee48572019-03-28 16:54:15 +0530258 if (blsp == 1) {
259 switch (qup) {
260 case 0:
261 clock_enable(&gcc->blsp1_qup0_spi_apps_cbcr);
262 break;
263 case 1:
264 clock_enable(&gcc->blsp1_qup1_spi_apps_cbcr);
265 break;
266 case 2:
267 clock_enable(&gcc->blsp1_qup2_spi_apps_cbcr);
268 break;
269 case 3:
270 clock_enable(&gcc->blsp1_qup3_spi_apps_cbcr);
271 break;
272 case 4:
273 clock_enable(&gcc->blsp1_qup4_spi_apps_cbcr);
274 break;
275 }
276 } else if (blsp == 2)
277 clock_enable(&gcc->blsp2_qup0_spi_apps_cbcr);
278 else
279 printk(BIOS_ERR, "BLSP%d not supported\n", blsp);
Pranav Agrawale651e012018-11-20 18:16:26 +0530280}
281
Taniya Das3ee48572019-03-28 16:54:15 +0530282void clock_disable_spi(int blsp, int qup)
Pranav Agrawale651e012018-11-20 18:16:26 +0530283{
Taniya Das3ee48572019-03-28 16:54:15 +0530284 if (blsp == 1) {
285 switch (qup) {
286 case 0:
287 clock_enable(&gcc->blsp1_qup0_spi_apps_cbcr);
288 break;
289 case 1:
290 clock_enable(&gcc->blsp1_qup1_spi_apps_cbcr);
291 break;
292 case 2:
293 clock_enable(&gcc->blsp1_qup2_spi_apps_cbcr);
294 break;
295 case 3:
296 clock_enable(&gcc->blsp1_qup3_spi_apps_cbcr);
297 break;
298 case 4:
299 clock_enable(&gcc->blsp1_qup4_spi_apps_cbcr);
300 break;
301 }
302 } else if (blsp == 2)
303 clock_enable(&gcc->blsp2_qup0_spi_apps_cbcr);
304 else
305 printk(BIOS_ERR, "BLSP%d not supported\n", blsp);
306
Pranav Agrawale651e012018-11-20 18:16:26 +0530307}
308
Taniya Das846f8c02019-04-17 15:58:15 +0530309void clock_enable_i2c(void)
310{
311 clock_enable(&gcc->blsp1_qup1_i2c_apps_cbcr);
312}
313
314void clock_disable_i2c(void)
315{
316 clock_disable(&gcc->blsp1_qup1_i2c_apps_cbcr);
317}
318
Pranav Agrawale651e012018-11-20 18:16:26 +0530319void clock_init(void)
320{
Pranav Agrawale651e012018-11-20 18:16:26 +0530321 clock_configure_gpll0();
Pranav Agrawale651e012018-11-20 18:16:26 +0530322 clock_enable_vote(&gcc->blsp1_ahb_cbcr,
323 &gcc->gcc_apcs_clock_branch_en_vote,
324 BLSP1_AHB_CLK_ENA);
325
Pranav Agrawale651e012018-11-20 18:16:26 +0530326 clock_enable_vote(&gcc->blsp2_ahb_cbcr,
327 &gcc->gcc_apcs_clock_branch_en_vote,
328 BLSP2_AHB_CLK_ENA);
329}