1 /* This file is part of the coreboot project.
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
14 #include <console/console.h>
15 #include <device/mmio.h>
17 #include <commonlib/helpers.h>
18 #include <soc/clock.h>
20 #define DIV(div) (div ? (2*div - 1) : 0)
21 #define HALF_DIVIDER(div2x) (div2x ? (div2x - 1) : 0)
23 struct clock_config uart_cfg
[] = {
27 .src
= SRC_GPLL0_MAIN_800MHZ
,
36 .src
= SRC_GPLL0_MAIN_800MHZ
,
44 struct clock_config i2c_cfg
[] = {
48 .src
= SRC_XO_19_2MHZ
,
54 .src
= SRC_GPLL0_MAIN_800MHZ
,
59 struct clock_config spi_cfg
[] = {
63 .src
= SRC_XO_19_2MHZ
,
68 .src
= SRC_GPLL0_MAIN_800MHZ
,
77 .src
= SRC_XO_19_2MHZ
,
83 .src
= SRC_XO_19_2MHZ
,
89 .src
= SRC_GPLL0_MAIN_800MHZ
,
94 static int clock_configure_gpll0(void)
96 /* Keep existing GPLL0 configuration, in RUN mode @800Mhz. */
97 setbits32(&gcc
->gpll0
.user_ctl
,
98 1 << CLK_CTL_GPLL_PLLOUT_LV_EARLY_SHFT
|
99 1 << CLK_CTL_GPLL_PLLOUT_AUX2_SHFT
|
100 1 << CLK_CTL_GPLL_PLLOUT_AUX_SHFT
|
101 1 << CLK_CTL_GPLL_PLLOUT_MAIN_SHFT
);
105 static int clock_configure_mnd(struct qcs405_clock
*clk
, uint32_t m
, uint32_t n
,
110 /* Configure Root Clock Generator(RCG) for Dual Edge Mode */
111 reg_val
= read32(&clk
->rcg
.cfg
);
112 reg_val
|= (2 << CLK_CTL_CFG_MODE_SHFT
);
113 write32(&clk
->rcg
.cfg
, reg_val
);
115 /* Set M/N/D config */
116 write32(&clk
->m
, m
& CLK_CTL_RCG_MND_BMSK
);
117 write32(&clk
->n
, ~(n
-m
) & CLK_CTL_RCG_MND_BMSK
);
118 write32(&clk
->d_2
, ~(d_2
) & CLK_CTL_RCG_MND_BMSK
);
123 static int clock_configure(struct qcs405_clock
*clk
,
124 struct clock_config
*clk_cfg
,
125 uint32_t hz
, uint32_t num_perfs
)
130 for (idx
= 0; idx
< num_perfs
; idx
++)
131 if (hz
<= clk_cfg
[idx
].hz
)
134 reg_val
= (clk_cfg
[idx
].src
<< CLK_CTL_CFG_SRC_SEL_SHFT
) |
135 (clk_cfg
[idx
].div
<< CLK_CTL_CFG_SRC_DIV_SHFT
);
137 /* Set clock config */
138 write32(&clk
->rcg
.cfg
, reg_val
);
140 if (clk_cfg
[idx
].m
!= 0)
141 clock_configure_mnd(clk
, clk_cfg
[idx
].m
, clk_cfg
[idx
].n
,
144 /* Commit config to RCG*/
145 setbits32(&clk
->rcg
.cmd
, BIT(CLK_CTL_CMD_UPDATE_SHFT
));
150 static bool clock_is_off(void *cbcr_addr
)
152 return (read32(cbcr_addr
) & CLK_CTL_CBC_CLK_OFF_BMSK
);
155 static int clock_enable_vote(void *cbcr_addr
, void *vote_addr
,
159 /* Set clock vote bit */
160 setbits32(vote_addr
, BIT(vote_bit
));
162 /* Ensure clock is enabled */
163 while (clock_is_off(cbcr_addr
));
168 static int clock_enable(void *cbcr_addr
)
171 /* Set clock enable bit */
172 setbits32(cbcr_addr
, BIT(CLK_CTL_CBC_CLK_EN_SHFT
));
174 /* Ensure clock is enabled */
175 while (clock_is_off(cbcr_addr
))
181 static int clock_disable(void *cbcr_addr
)
184 /* Set clock enable bit */
185 clrbits32(cbcr_addr
, BIT(CLK_CTL_CBC_CLK_EN_SHFT
));
189 int clock_reset_bcr(void *bcr_addr
, bool reset
)
191 struct qcs405_bcr
*bcr
= bcr_addr
;
194 setbits32(&bcr
->bcr
, BIT(CLK_CTL_BCR_BLK_ARES_SHFT
));
196 clrbits32(&bcr
->bcr
, BIT(CLK_CTL_BCR_BLK_ARES_SHFT
));
201 void clock_configure_uart(uint32_t hz
)
203 struct qcs405_clock
*uart_clk
= (struct qcs405_clock
*)
204 &gcc
->blsp1_uart2_apps_clk
;
206 clock_configure(uart_clk
, uart_cfg
, hz
, ARRAY_SIZE(uart_cfg
));
209 void clock_configure_spi(int blsp
, int qup
, uint32_t hz
)
211 struct qcs405_clock
*spi_clk
= 0;
216 spi_clk
= (struct qcs405_clock
*)
217 &gcc
->blsp1_qup0_spi_clk
;
220 spi_clk
= (struct qcs405_clock
*)
221 &gcc
->blsp1_qup1_spi_clk
;
224 spi_clk
= (struct qcs405_clock
*)
225 &gcc
->blsp1_qup2_spi_clk
;
228 spi_clk
= (struct qcs405_clock
*)
229 &gcc
->blsp1_qup3_spi_clk
;
232 spi_clk
= (struct qcs405_clock
*)
233 &gcc
->blsp1_qup4_spi_clk
;
236 printk(BIOS_ERR
, "Invalid QUP %d\n", qup
);
239 } else if (blsp
== 2) {
240 spi_clk
= (struct qcs405_clock
*)&gcc
->blsp2_qup0_spi_clk
;
242 printk(BIOS_ERR
, "BLSP %d not supported\n", blsp
);
246 clock_configure(spi_clk
, spi_cfg
, hz
, ARRAY_SIZE(spi_cfg
));
249 void clock_configure_i2c(uint32_t hz
)
251 struct qcs405_clock
*i2c_clk
=
252 (struct qcs405_clock
*)&gcc
->blsp1_qup1_i2c_clk
;
254 clock_configure(i2c_clk
, i2c_cfg
, hz
, ARRAY_SIZE(i2c_cfg
));
257 void clock_enable_uart(void)
259 clock_enable(&gcc
->blsp1_uart2_apps_cbcr
);
262 void clock_disable_uart(void)
264 clock_disable(&gcc
->blsp1_uart2_apps_cbcr
);
267 void clock_enable_spi(int blsp
, int qup
)
272 clock_enable(&gcc
->blsp1_qup0_spi_apps_cbcr
);
275 clock_enable(&gcc
->blsp1_qup1_spi_apps_cbcr
);
278 clock_enable(&gcc
->blsp1_qup2_spi_apps_cbcr
);
281 clock_enable(&gcc
->blsp1_qup3_spi_apps_cbcr
);
284 clock_enable(&gcc
->blsp1_qup4_spi_apps_cbcr
);
287 } else if (blsp
== 2)
288 clock_enable(&gcc
->blsp2_qup0_spi_apps_cbcr
);
290 printk(BIOS_ERR
, "BLSP%d not supported\n", blsp
);
293 void clock_disable_spi(int blsp
, int qup
)
298 clock_enable(&gcc
->blsp1_qup0_spi_apps_cbcr
);
301 clock_enable(&gcc
->blsp1_qup1_spi_apps_cbcr
);
304 clock_enable(&gcc
->blsp1_qup2_spi_apps_cbcr
);
307 clock_enable(&gcc
->blsp1_qup3_spi_apps_cbcr
);
310 clock_enable(&gcc
->blsp1_qup4_spi_apps_cbcr
);
313 } else if (blsp
== 2)
314 clock_enable(&gcc
->blsp2_qup0_spi_apps_cbcr
);
316 printk(BIOS_ERR
, "BLSP%d not supported\n", blsp
);
320 void clock_enable_i2c(void)
322 clock_enable(&gcc
->blsp1_qup1_i2c_apps_cbcr
);
325 void clock_disable_i2c(void)
327 clock_disable(&gcc
->blsp1_qup1_i2c_apps_cbcr
);
330 void clock_init(void)
332 clock_configure_gpll0();
333 clock_enable_vote(&gcc
->blsp1_ahb_cbcr
,
334 &gcc
->gcc_apcs_clock_branch_en_vote
,
337 clock_enable_vote(&gcc
->blsp2_ahb_cbcr
,
338 &gcc
->gcc_apcs_clock_branch_en_vote
,