blob: 17d8dcd5c841c6bb828658d86bc21c6f4d2d3cdc [file] [log] [blame]
Tom Rini10e47792018-05-06 17:58:06 -04001// SPDX-License-Identifier: GPL-2.0+
Jason Liudec11122011-11-25 00:18:02 +00002/*
3 * Copyright (C) 2010-2011 Freescale Semiconductor, Inc.
Jason Liudec11122011-11-25 00:18:02 +00004 */
5
6#include <common.h>
Simon Glassed38aef2020-05-10 11:40:03 -06007#include <command.h>
Christian Gmeinere5848142014-01-08 08:24:25 +01008#include <div64.h>
Simon Glass0f2af882020-05-10 11:40:05 -06009#include <log.h>
Jason Liudec11122011-11-25 00:18:02 +000010#include <asm/io.h>
Masahiro Yamada56a931c2016-09-21 11:28:55 +090011#include <linux/errno.h>
Jason Liudec11122011-11-25 00:18:02 +000012#include <asm/arch/imx-regs.h>
Fabio Estevam6479f512012-04-29 08:11:13 +000013#include <asm/arch/crm_regs.h>
Jason Liudec11122011-11-25 00:18:02 +000014#include <asm/arch/clock.h>
Fabio Estevam6479f512012-04-29 08:11:13 +000015#include <asm/arch/sys_proto.h>
Jason Liudec11122011-11-25 00:18:02 +000016
17enum pll_clocks {
18 PLL_SYS, /* System PLL */
19 PLL_BUS, /* System Bus PLL*/
20 PLL_USBOTG, /* OTG USB PLL */
21 PLL_ENET, /* ENET PLL */
Peng Fanbd0c46f2016-01-06 11:06:31 +080022 PLL_AUDIO, /* AUDIO PLL */
Anatolij Gustschin705d5d72017-08-02 16:05:12 +020023 PLL_VIDEO, /* VIDEO PLL */
Jason Liudec11122011-11-25 00:18:02 +000024};
25
Fabio Estevam6479f512012-04-29 08:11:13 +000026struct mxc_ccm_reg *imx_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
Jason Liudec11122011-11-25 00:18:02 +000027
Benoît Thébaudeau20db6312013-04-23 10:17:44 +000028#ifdef CONFIG_MXC_OCOTP
29void enable_ocotp_clk(unsigned char enable)
30{
31 u32 reg;
32
33 reg = __raw_readl(&imx_ccm->CCGR2);
34 if (enable)
35 reg |= MXC_CCM_CCGR2_OCOTP_CTRL_MASK;
36 else
37 reg &= ~MXC_CCM_CCGR2_OCOTP_CTRL_MASK;
38 __raw_writel(reg, &imx_ccm->CCGR2);
39}
40#endif
41
Nikita Kiryanov98b76b42014-08-20 15:08:49 +030042#ifdef CONFIG_NAND_MXS
43void setup_gpmi_io_clk(u32 cfg)
44{
45 /* Disable clocks per ERR007177 from MX6 errata */
46 clrbits_le32(&imx_ccm->CCGR4,
47 MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK |
48 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK |
49 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK |
50 MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK |
51 MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_MASK);
52
Ye.Li1475bff2015-01-12 16:46:17 +080053#if defined(CONFIG_MX6SX)
54 clrbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK);
55
56 clrsetbits_le32(&imx_ccm->cs2cdr,
57 MXC_CCM_CS2CDR_QSPI2_CLK_PODF_MASK |
58 MXC_CCM_CS2CDR_QSPI2_CLK_PRED_MASK |
59 MXC_CCM_CS2CDR_QSPI2_CLK_SEL_MASK,
60 cfg);
61
62 setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK);
63#else
Nikita Kiryanov98b76b42014-08-20 15:08:49 +030064 clrbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK);
65
66 clrsetbits_le32(&imx_ccm->cs2cdr,
67 MXC_CCM_CS2CDR_ENFC_CLK_PODF_MASK |
68 MXC_CCM_CS2CDR_ENFC_CLK_PRED_MASK |
69 MXC_CCM_CS2CDR_ENFC_CLK_SEL_MASK,
70 cfg);
71
72 setbits_le32(&imx_ccm->CCGR2, MXC_CCM_CCGR2_IOMUX_IPT_CLK_IO_MASK);
Ye.Li1475bff2015-01-12 16:46:17 +080073#endif
Nikita Kiryanov98b76b42014-08-20 15:08:49 +030074 setbits_le32(&imx_ccm->CCGR4,
75 MXC_CCM_CCGR4_RAWNAND_U_BCH_INPUT_APB_MASK |
76 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_BCH_MASK |
77 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK |
78 MXC_CCM_CCGR4_RAWNAND_U_GPMI_INPUT_APB_MASK |
79 MXC_CCM_CCGR4_PL301_MX6QPER1_BCH_MASK);
80}
81#endif
82
Wolfgang Grandegger1859b702012-02-08 22:33:25 +000083void enable_usboh3_clk(unsigned char enable)
84{
85 u32 reg;
86
87 reg = __raw_readl(&imx_ccm->CCGR6);
88 if (enable)
Eric Nelsone4279542012-09-21 07:33:51 +000089 reg |= MXC_CCM_CCGR6_USBOH3_MASK;
Wolfgang Grandegger1859b702012-02-08 22:33:25 +000090 else
Eric Nelsone4279542012-09-21 07:33:51 +000091 reg &= ~(MXC_CCM_CCGR6_USBOH3_MASK);
Wolfgang Grandegger1859b702012-02-08 22:33:25 +000092 __raw_writel(reg, &imx_ccm->CCGR6);
93
Nikita Kiryanov98b76b42014-08-20 15:08:49 +030094}
95
Stefano Babic198249b2014-09-10 13:02:40 +020096#if defined(CONFIG_FEC_MXC) && !defined(CONFIG_MX6SX)
Nikita Kiryanov98b76b42014-08-20 15:08:49 +030097void enable_enet_clk(unsigned char enable)
98{
Peng Fan40a6ed12015-07-20 19:28:27 +080099 u32 mask, *addr;
100
Peng Fance7a7122016-08-11 14:02:47 +0800101 if (is_mx6ull()) {
102 mask = MXC_CCM_CCGR0_ENET_CLK_ENABLE_MASK;
103 addr = &imx_ccm->CCGR0;
104 } else if (is_mx6ul()) {
Peng Fan40a6ed12015-07-20 19:28:27 +0800105 mask = MXC_CCM_CCGR3_ENET_MASK;
106 addr = &imx_ccm->CCGR3;
107 } else {
108 mask = MXC_CCM_CCGR1_ENET_MASK;
109 addr = &imx_ccm->CCGR1;
110 }
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300111
112 if (enable)
Peng Fan40a6ed12015-07-20 19:28:27 +0800113 setbits_le32(addr, mask);
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300114 else
Peng Fan40a6ed12015-07-20 19:28:27 +0800115 clrbits_le32(addr, mask);
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300116}
117#endif
118
119#ifdef CONFIG_MXC_UART
120void enable_uart_clk(unsigned char enable)
121{
Peng Fan40a6ed12015-07-20 19:28:27 +0800122 u32 mask;
123
Peng Fance7a7122016-08-11 14:02:47 +0800124 if (is_mx6ul() || is_mx6ull())
Peng Fan40a6ed12015-07-20 19:28:27 +0800125 mask = MXC_CCM_CCGR5_UART_MASK;
126 else
127 mask = MXC_CCM_CCGR5_UART_MASK | MXC_CCM_CCGR5_UART_SERIAL_MASK;
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300128
129 if (enable)
130 setbits_le32(&imx_ccm->CCGR5, mask);
131 else
132 clrbits_le32(&imx_ccm->CCGR5, mask);
133}
134#endif
135
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300136#ifdef CONFIG_MMC
137int enable_usdhc_clk(unsigned char enable, unsigned bus_num)
138{
139 u32 mask;
140
141 if (bus_num > 3)
142 return -EINVAL;
143
144 mask = MXC_CCM_CCGR_CG_MASK << (bus_num * 2 + 2);
145 if (enable)
146 setbits_le32(&imx_ccm->CCGR6, mask);
147 else
148 clrbits_le32(&imx_ccm->CCGR6, mask);
149
150 return 0;
Wolfgang Grandegger1859b702012-02-08 22:33:25 +0000151}
Nikita Kiryanov98b76b42014-08-20 15:08:49 +0300152#endif
Wolfgang Grandegger1859b702012-02-08 22:33:25 +0000153
trema49f40a2013-09-21 18:13:35 +0200154#ifdef CONFIG_SYS_I2C_MXC
Heiko Schocher5c4b1e92015-05-18 10:56:24 +0200155/* i2c_num can be from 0 - 3 */
Troy Kiskyd4fdc992012-07-19 08:18:25 +0000156int enable_i2c_clk(unsigned char enable, unsigned i2c_num)
157{
158 u32 reg;
159 u32 mask;
Peng Fand847db72015-07-01 17:01:50 +0800160 u32 *addr;
Troy Kiskyd4fdc992012-07-19 08:18:25 +0000161
Heiko Schocher5c4b1e92015-05-18 10:56:24 +0200162 if (i2c_num > 3)
Troy Kiskyd4fdc992012-07-19 08:18:25 +0000163 return -EINVAL;
Heiko Schocher5c4b1e92015-05-18 10:56:24 +0200164 if (i2c_num < 3) {
165 mask = MXC_CCM_CCGR_CG_MASK
166 << (MXC_CCM_CCGR2_I2C1_SERIAL_OFFSET
167 + (i2c_num << 1));
168 reg = __raw_readl(&imx_ccm->CCGR2);
169 if (enable)
170 reg |= mask;
171 else
172 reg &= ~mask;
173 __raw_writel(reg, &imx_ccm->CCGR2);
174 } else {
Peng Fan7e2e2092016-12-11 19:24:29 +0800175 if (is_mx6sll())
176 return -EINVAL;
Peng Fance7a7122016-08-11 14:02:47 +0800177 if (is_mx6sx() || is_mx6ul() || is_mx6ull()) {
Peng Fand847db72015-07-01 17:01:50 +0800178 mask = MXC_CCM_CCGR6_I2C4_MASK;
179 addr = &imx_ccm->CCGR6;
180 } else {
181 mask = MXC_CCM_CCGR1_I2C4_SERIAL_MASK;
182 addr = &imx_ccm->CCGR1;
183 }
184 reg = __raw_readl(addr);
Heiko Schocher5c4b1e92015-05-18 10:56:24 +0200185 if (enable)
186 reg |= mask;
187 else
188 reg &= ~mask;
Peng Fand847db72015-07-01 17:01:50 +0800189 __raw_writel(reg, addr);
Heiko Schocher5c4b1e92015-05-18 10:56:24 +0200190 }
Troy Kiskyd4fdc992012-07-19 08:18:25 +0000191 return 0;
192}
193#endif
194
Heiko Schocher472a68f2014-07-18 06:07:20 +0200195/* spi_num can be from 0 - SPI_MAX_NUM */
196int enable_spi_clk(unsigned char enable, unsigned spi_num)
197{
198 u32 reg;
199 u32 mask;
200
201 if (spi_num > SPI_MAX_NUM)
202 return -EINVAL;
203
204 mask = MXC_CCM_CCGR_CG_MASK << (spi_num << 1);
205 reg = __raw_readl(&imx_ccm->CCGR1);
206 if (enable)
207 reg |= mask;
208 else
209 reg &= ~mask;
210 __raw_writel(reg, &imx_ccm->CCGR1);
211 return 0;
212}
Jason Liudec11122011-11-25 00:18:02 +0000213static u32 decode_pll(enum pll_clocks pll, u32 infreq)
214{
Peng Fanbd0c46f2016-01-06 11:06:31 +0800215 u32 div, test_div, pll_num, pll_denom;
Dario Binacchi32d74902023-04-22 16:11:17 +0200216 u64 temp64;
Jason Liudec11122011-11-25 00:18:02 +0000217
218 switch (pll) {
219 case PLL_SYS:
220 div = __raw_readl(&imx_ccm->analog_pll_sys);
221 div &= BM_ANADIG_PLL_SYS_DIV_SELECT;
222
Andre Renaudb0be82e2014-06-10 08:47:13 +1200223 return (infreq * div) >> 1;
Jason Liudec11122011-11-25 00:18:02 +0000224 case PLL_BUS:
225 div = __raw_readl(&imx_ccm->analog_pll_528);
226 div &= BM_ANADIG_PLL_528_DIV_SELECT;
227
228 return infreq * (20 + (div << 1));
229 case PLL_USBOTG:
230 div = __raw_readl(&imx_ccm->analog_usb1_pll_480_ctrl);
231 div &= BM_ANADIG_USB1_PLL_480_CTRL_DIV_SELECT;
232
233 return infreq * (20 + (div << 1));
234 case PLL_ENET:
235 div = __raw_readl(&imx_ccm->analog_pll_enet);
236 div &= BM_ANADIG_PLL_ENET_DIV_SELECT;
237
Fabio Estevam93bc8ea2013-12-03 18:26:13 -0200238 return 25000000 * (div + (div >> 1) + 1);
Peng Fanbd0c46f2016-01-06 11:06:31 +0800239 case PLL_AUDIO:
240 div = __raw_readl(&imx_ccm->analog_pll_audio);
241 if (!(div & BM_ANADIG_PLL_AUDIO_ENABLE))
242 return 0;
243 /* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
244 if (div & BM_ANADIG_PLL_AUDIO_BYPASS)
245 return MXC_HCLK;
246 pll_num = __raw_readl(&imx_ccm->analog_pll_audio_num);
247 pll_denom = __raw_readl(&imx_ccm->analog_pll_audio_denom);
248 test_div = (div & BM_ANADIG_PLL_AUDIO_TEST_DIV_SELECT) >>
249 BP_ANADIG_PLL_AUDIO_TEST_DIV_SELECT;
250 div &= BM_ANADIG_PLL_AUDIO_DIV_SELECT;
251 if (test_div == 3) {
252 debug("Error test_div\n");
253 return 0;
254 }
255 test_div = 1 << (2 - test_div);
256
257 return infreq * (div + pll_num / pll_denom) / test_div;
258 case PLL_VIDEO:
259 div = __raw_readl(&imx_ccm->analog_pll_video);
260 if (!(div & BM_ANADIG_PLL_VIDEO_ENABLE))
261 return 0;
262 /* BM_ANADIG_PLL_AUDIO_BYPASS_CLK_SRC is ignored */
263 if (div & BM_ANADIG_PLL_VIDEO_BYPASS)
264 return MXC_HCLK;
265 pll_num = __raw_readl(&imx_ccm->analog_pll_video_num);
266 pll_denom = __raw_readl(&imx_ccm->analog_pll_video_denom);
267 test_div = (div & BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT) >>
268 BP_ANADIG_PLL_VIDEO_POST_DIV_SELECT;
269 div &= BM_ANADIG_PLL_VIDEO_DIV_SELECT;
270 if (test_div == 3) {
271 debug("Error test_div\n");
272 return 0;
273 }
274 test_div = 1 << (2 - test_div);
275
Dario Binacchi32d74902023-04-22 16:11:17 +0200276 temp64 = (u64)infreq;
277 temp64 *= pll_num;
278 do_div(temp64, pll_denom);
279 return infreq * div + (unsigned long)temp64;
Jason Liudec11122011-11-25 00:18:02 +0000280 default:
281 return 0;
282 }
283 /* NOTREACHED */
284}
Pierre Auberte8e62a72013-09-19 17:48:59 +0200285static u32 mxc_get_pll_pfd(enum pll_clocks pll, int pfd_num)
286{
287 u32 div;
288 u64 freq;
289
290 switch (pll) {
291 case PLL_BUS:
Peng Fance7a7122016-08-11 14:02:47 +0800292 if (!is_mx6ul() && !is_mx6ull()) {
Peng Fan40a6ed12015-07-20 19:28:27 +0800293 if (pfd_num == 3) {
Peng Fan8bed5f92016-06-30 21:08:00 +0800294 /* No PFD3 on PLL2 */
Peng Fan40a6ed12015-07-20 19:28:27 +0800295 return 0;
296 }
Pierre Auberte8e62a72013-09-19 17:48:59 +0200297 }
298 div = __raw_readl(&imx_ccm->analog_pfd_528);
299 freq = (u64)decode_pll(PLL_BUS, MXC_HCLK);
300 break;
301 case PLL_USBOTG:
302 div = __raw_readl(&imx_ccm->analog_pfd_480);
303 freq = (u64)decode_pll(PLL_USBOTG, MXC_HCLK);
304 break;
305 default:
306 /* No PFD on other PLL */
307 return 0;
308 }
309
Christian Gmeinere5848142014-01-08 08:24:25 +0100310 return lldiv(freq * 18, (div & ANATOP_PFD_FRAC_MASK(pfd_num)) >>
Pierre Auberte8e62a72013-09-19 17:48:59 +0200311 ANATOP_PFD_FRAC_SHIFT(pfd_num));
312}
Jason Liudec11122011-11-25 00:18:02 +0000313
314static u32 get_mcu_main_clk(void)
315{
316 u32 reg, freq;
317
318 reg = __raw_readl(&imx_ccm->cacrr);
319 reg &= MXC_CCM_CACRR_ARM_PODF_MASK;
320 reg >>= MXC_CCM_CACRR_ARM_PODF_OFFSET;
Benoît Thébaudeauafac1652012-09-27 10:19:58 +0000321 freq = decode_pll(PLL_SYS, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +0000322
323 return freq / (reg + 1);
324}
325
Fabio Estevam6479f512012-04-29 08:11:13 +0000326u32 get_periph_clk(void)
Jason Liudec11122011-11-25 00:18:02 +0000327{
Peng Fan40a6ed12015-07-20 19:28:27 +0800328 u32 reg, div = 0, freq = 0;
Jason Liudec11122011-11-25 00:18:02 +0000329
330 reg = __raw_readl(&imx_ccm->cbcdr);
331 if (reg & MXC_CCM_CBCDR_PERIPH_CLK_SEL) {
Peng Fan40a6ed12015-07-20 19:28:27 +0800332 div = (reg & MXC_CCM_CBCDR_PERIPH_CLK2_PODF_MASK) >>
333 MXC_CCM_CBCDR_PERIPH_CLK2_PODF_OFFSET;
Jason Liudec11122011-11-25 00:18:02 +0000334 reg = __raw_readl(&imx_ccm->cbcmr);
335 reg &= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_MASK;
336 reg >>= MXC_CCM_CBCMR_PERIPH_CLK2_SEL_OFFSET;
337
338 switch (reg) {
339 case 0:
Benoît Thébaudeauafac1652012-09-27 10:19:58 +0000340 freq = decode_pll(PLL_USBOTG, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +0000341 break;
342 case 1:
343 case 2:
Benoît Thébaudeauafac1652012-09-27 10:19:58 +0000344 freq = MXC_HCLK;
Jason Liudec11122011-11-25 00:18:02 +0000345 break;
346 default:
347 break;
348 }
349 } else {
350 reg = __raw_readl(&imx_ccm->cbcmr);
351 reg &= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_MASK;
352 reg >>= MXC_CCM_CBCMR_PRE_PERIPH_CLK_SEL_OFFSET;
353
354 switch (reg) {
355 case 0:
Benoît Thébaudeauafac1652012-09-27 10:19:58 +0000356 freq = decode_pll(PLL_BUS, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +0000357 break;
358 case 1:
Pierre Auberte8e62a72013-09-19 17:48:59 +0200359 freq = mxc_get_pll_pfd(PLL_BUS, 2);
Jason Liudec11122011-11-25 00:18:02 +0000360 break;
361 case 2:
Pierre Auberte8e62a72013-09-19 17:48:59 +0200362 freq = mxc_get_pll_pfd(PLL_BUS, 0);
Jason Liudec11122011-11-25 00:18:02 +0000363 break;
364 case 3:
Pierre Auberte8e62a72013-09-19 17:48:59 +0200365 /* static / 2 divider */
366 freq = mxc_get_pll_pfd(PLL_BUS, 2) / 2;
Jason Liudec11122011-11-25 00:18:02 +0000367 break;
368 default:
369 break;
370 }
371 }
372
Peng Fan40a6ed12015-07-20 19:28:27 +0800373 return freq / (div + 1);
Jason Liudec11122011-11-25 00:18:02 +0000374}
375
Jason Liudec11122011-11-25 00:18:02 +0000376static u32 get_ipg_clk(void)
377{
378 u32 reg, ipg_podf;
379
380 reg = __raw_readl(&imx_ccm->cbcdr);
381 reg &= MXC_CCM_CBCDR_IPG_PODF_MASK;
382 ipg_podf = reg >> MXC_CCM_CBCDR_IPG_PODF_OFFSET;
383
384 return get_ahb_clk() / (ipg_podf + 1);
385}
386
387static u32 get_ipg_per_clk(void)
388{
389 u32 reg, perclk_podf;
390
391 reg = __raw_readl(&imx_ccm->cscmr1);
Peng Fan7e2e2092016-12-11 19:24:29 +0800392 if (is_mx6sll() || is_mx6sl() || is_mx6sx() ||
Peng Fance7a7122016-08-11 14:02:47 +0800393 is_mx6dqp() || is_mx6ul() || is_mx6ull()) {
Peng Fan53f3c9e2015-07-11 11:38:43 +0800394 if (reg & MXC_CCM_CSCMR1_PER_CLK_SEL_MASK)
395 return MXC_HCLK; /* OSC 24Mhz */
396 }
397
Jason Liudec11122011-11-25 00:18:02 +0000398 perclk_podf = reg & MXC_CCM_CSCMR1_PERCLK_PODF_MASK;
399
400 return get_ipg_clk() / (perclk_podf + 1);
401}
402
403static u32 get_uart_clk(void)
404{
405 u32 reg, uart_podf;
Pierre Auberte8e62a72013-09-19 17:48:59 +0200406 u32 freq = decode_pll(PLL_USBOTG, MXC_HCLK) / 6; /* static divider */
Jason Liudec11122011-11-25 00:18:02 +0000407 reg = __raw_readl(&imx_ccm->cscdr1);
Peng Fan53f3c9e2015-07-11 11:38:43 +0800408
Peng Fance7a7122016-08-11 14:02:47 +0800409 if (is_mx6sl() || is_mx6sx() || is_mx6dqp() || is_mx6ul() ||
Peng Fan7e2e2092016-12-11 19:24:29 +0800410 is_mx6sll() || is_mx6ull()) {
Peng Fan53f3c9e2015-07-11 11:38:43 +0800411 if (reg & MXC_CCM_CSCDR1_UART_CLK_SEL)
412 freq = MXC_HCLK;
413 }
414
Jason Liudec11122011-11-25 00:18:02 +0000415 reg &= MXC_CCM_CSCDR1_UART_CLK_PODF_MASK;
416 uart_podf = reg >> MXC_CCM_CSCDR1_UART_CLK_PODF_OFFSET;
417
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000418 return freq / (uart_podf + 1);
Jason Liudec11122011-11-25 00:18:02 +0000419}
420
421static u32 get_cspi_clk(void)
422{
423 u32 reg, cspi_podf;
424
425 reg = __raw_readl(&imx_ccm->cscdr2);
Peng Fan53f3c9e2015-07-11 11:38:43 +0800426 cspi_podf = (reg & MXC_CCM_CSCDR2_ECSPI_CLK_PODF_MASK) >>
427 MXC_CCM_CSCDR2_ECSPI_CLK_PODF_OFFSET;
428
Peng Fance7a7122016-08-11 14:02:47 +0800429 if (is_mx6dqp() || is_mx6sl() || is_mx6sx() || is_mx6ul() ||
Peng Fan7e2e2092016-12-11 19:24:29 +0800430 is_mx6sll() || is_mx6ull()) {
Peng Fan53f3c9e2015-07-11 11:38:43 +0800431 if (reg & MXC_CCM_CSCDR2_ECSPI_CLK_SEL_MASK)
432 return MXC_HCLK / (cspi_podf + 1);
433 }
Jason Liudec11122011-11-25 00:18:02 +0000434
Pierre Auberte8e62a72013-09-19 17:48:59 +0200435 return decode_pll(PLL_USBOTG, MXC_HCLK) / (8 * (cspi_podf + 1));
Jason Liudec11122011-11-25 00:18:02 +0000436}
437
438static u32 get_axi_clk(void)
439{
440 u32 root_freq, axi_podf;
441 u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
442
443 axi_podf = cbcdr & MXC_CCM_CBCDR_AXI_PODF_MASK;
444 axi_podf >>= MXC_CCM_CBCDR_AXI_PODF_OFFSET;
445
446 if (cbcdr & MXC_CCM_CBCDR_AXI_SEL) {
447 if (cbcdr & MXC_CCM_CBCDR_AXI_ALT_SEL)
Pierre Auberte8e62a72013-09-19 17:48:59 +0200448 root_freq = mxc_get_pll_pfd(PLL_USBOTG, 1);
Fabio Estevam50f78c92016-07-18 10:19:28 -0300449 else
450 root_freq = mxc_get_pll_pfd(PLL_BUS, 2);
Jason Liudec11122011-11-25 00:18:02 +0000451 } else
452 root_freq = get_periph_clk();
453
454 return root_freq / (axi_podf + 1);
455}
456
457static u32 get_emi_slow_clk(void)
458{
Andrew Gabbasov4740e242013-07-04 06:27:32 -0500459 u32 emi_clk_sel, emi_slow_podf, cscmr1, root_freq = 0;
Jason Liudec11122011-11-25 00:18:02 +0000460
461 cscmr1 = __raw_readl(&imx_ccm->cscmr1);
462 emi_clk_sel = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_MASK;
463 emi_clk_sel >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_OFFSET;
Andrew Gabbasov4740e242013-07-04 06:27:32 -0500464 emi_slow_podf = cscmr1 & MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_MASK;
465 emi_slow_podf >>= MXC_CCM_CSCMR1_ACLK_EMI_SLOW_PODF_OFFSET;
Jason Liudec11122011-11-25 00:18:02 +0000466
467 switch (emi_clk_sel) {
468 case 0:
469 root_freq = get_axi_clk();
470 break;
471 case 1:
Benoît Thébaudeauafac1652012-09-27 10:19:58 +0000472 root_freq = decode_pll(PLL_USBOTG, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +0000473 break;
474 case 2:
Pierre Auberte8e62a72013-09-19 17:48:59 +0200475 root_freq = mxc_get_pll_pfd(PLL_BUS, 2);
Jason Liudec11122011-11-25 00:18:02 +0000476 break;
477 case 3:
Pierre Auberte8e62a72013-09-19 17:48:59 +0200478 root_freq = mxc_get_pll_pfd(PLL_BUS, 0);
Jason Liudec11122011-11-25 00:18:02 +0000479 break;
480 }
481
Andrew Gabbasov4740e242013-07-04 06:27:32 -0500482 return root_freq / (emi_slow_podf + 1);
Jason Liudec11122011-11-25 00:18:02 +0000483}
484
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000485static u32 get_mmdc_ch0_clk(void)
486{
487 u32 cbcmr = __raw_readl(&imx_ccm->cbcmr);
488 u32 cbcdr = __raw_readl(&imx_ccm->cbcdr);
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000489
Peng Fanbd0c46f2016-01-06 11:06:31 +0800490 u32 freq, podf, per2_clk2_podf, pmu_misc2_audio_div;
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000491
Peng Fan7e2e2092016-12-11 19:24:29 +0800492 if (is_mx6sx() || is_mx6ul() || is_mx6ull() || is_mx6sl() ||
493 is_mx6sll()) {
Peng Fan40a6ed12015-07-20 19:28:27 +0800494 podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH1_PODF_MASK) >>
495 MXC_CCM_CBCDR_MMDC_CH1_PODF_OFFSET;
496 if (cbcdr & MXC_CCM_CBCDR_PERIPH2_CLK_SEL) {
497 per2_clk2_podf = (cbcdr & MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_MASK) >>
498 MXC_CCM_CBCDR_PERIPH2_CLK2_PODF_OFFSET;
Peng Fan6861c5a2016-05-23 18:35:54 +0800499 if (is_mx6sl()) {
Peng Fan40a6ed12015-07-20 19:28:27 +0800500 if (cbcmr & MXC_CCM_CBCMR_PERIPH2_CLK2_SEL)
501 freq = MXC_HCLK;
502 else
503 freq = decode_pll(PLL_USBOTG, MXC_HCLK);
504 } else {
505 if (cbcmr & MXC_CCM_CBCMR_PERIPH2_CLK2_SEL)
506 freq = decode_pll(PLL_BUS, MXC_HCLK);
507 else
508 freq = decode_pll(PLL_USBOTG, MXC_HCLK);
509 }
510 } else {
511 per2_clk2_podf = 0;
512 switch ((cbcmr &
513 MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_MASK) >>
514 MXC_CCM_CBCMR_PRE_PERIPH2_CLK_SEL_OFFSET) {
515 case 0:
516 freq = decode_pll(PLL_BUS, MXC_HCLK);
517 break;
518 case 1:
519 freq = mxc_get_pll_pfd(PLL_BUS, 2);
520 break;
521 case 2:
522 freq = mxc_get_pll_pfd(PLL_BUS, 0);
523 break;
524 case 3:
Peng Fan5dbddb12016-12-11 19:24:25 +0800525 if (is_mx6sl()) {
526 freq = mxc_get_pll_pfd(PLL_BUS, 2) >> 1;
527 break;
528 }
529
Peng Fanbd0c46f2016-01-06 11:06:31 +0800530 pmu_misc2_audio_div = PMU_MISC2_AUDIO_DIV(__raw_readl(&imx_ccm->pmu_misc2));
531 switch (pmu_misc2_audio_div) {
532 case 0:
533 case 2:
534 pmu_misc2_audio_div = 1;
535 break;
536 case 1:
537 pmu_misc2_audio_div = 2;
538 break;
539 case 3:
540 pmu_misc2_audio_div = 4;
541 break;
542 }
543 freq = decode_pll(PLL_AUDIO, MXC_HCLK) /
544 pmu_misc2_audio_div;
Peng Fan40a6ed12015-07-20 19:28:27 +0800545 break;
546 }
547 }
548 return freq / (podf + 1) / (per2_clk2_podf + 1);
549 } else {
550 podf = (cbcdr & MXC_CCM_CBCDR_MMDC_CH0_PODF_MASK) >>
551 MXC_CCM_CBCDR_MMDC_CH0_PODF_OFFSET;
552 return get_periph_clk() / (podf + 1);
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000553 }
Otavio Salvadordc074432013-12-16 20:44:05 -0200554}
Otavio Salvadordc074432013-12-16 20:44:05 -0200555
Peng Fan53ebda82015-10-29 15:54:47 +0800556#if defined(CONFIG_VIDEO_MXS)
557static int enable_pll_video(u32 pll_div, u32 pll_num, u32 pll_denom,
558 u32 post_div)
559{
560 u32 reg = 0;
561 ulong start;
562
563 debug("pll5 div = %d, num = %d, denom = %d\n",
564 pll_div, pll_num, pll_denom);
565
566 /* Power up PLL5 video */
567 writel(BM_ANADIG_PLL_VIDEO_POWERDOWN |
568 BM_ANADIG_PLL_VIDEO_BYPASS |
569 BM_ANADIG_PLL_VIDEO_DIV_SELECT |
570 BM_ANADIG_PLL_VIDEO_POST_DIV_SELECT,
571 &imx_ccm->analog_pll_video_clr);
572
573 /* Set div, num and denom */
574 switch (post_div) {
575 case 1:
576 writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
577 BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x2),
578 &imx_ccm->analog_pll_video_set);
579 break;
580 case 2:
581 writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
582 BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x1),
583 &imx_ccm->analog_pll_video_set);
584 break;
585 case 4:
586 writel(BF_ANADIG_PLL_VIDEO_DIV_SELECT(pll_div) |
587 BF_ANADIG_PLL_VIDEO_POST_DIV_SELECT(0x0),
588 &imx_ccm->analog_pll_video_set);
589 break;
590 default:
591 puts("Wrong test_div!\n");
592 return -EINVAL;
593 }
594
595 writel(BF_ANADIG_PLL_VIDEO_NUM_A(pll_num),
596 &imx_ccm->analog_pll_video_num);
597 writel(BF_ANADIG_PLL_VIDEO_DENOM_B(pll_denom),
598 &imx_ccm->analog_pll_video_denom);
599
600 /* Wait PLL5 lock */
601 start = get_timer(0); /* Get current timestamp */
602
603 do {
604 reg = readl(&imx_ccm->analog_pll_video);
605 if (reg & BM_ANADIG_PLL_VIDEO_LOCK) {
606 /* Enable PLL out */
607 writel(BM_ANADIG_PLL_VIDEO_ENABLE,
608 &imx_ccm->analog_pll_video_set);
609 return 0;
610 }
611 } while (get_timer(0) < (start + 10)); /* Wait 10ms */
612
613 puts("Lock PLL5 timeout\n");
614
615 return -ETIME;
616}
617
618/*
619 * 24M--> PLL_VIDEO -> LCDIFx_PRED -> LCDIFx_PODF -> LCD
620 *
621 * 'freq' using KHz as unit, see driver/video/mxsfb.c.
622 */
623void mxs_set_lcdclk(u32 base_addr, u32 freq)
624{
625 u32 reg = 0;
626 u32 hck = MXC_HCLK / 1000;
627 /* DIV_SELECT ranges from 27 to 54 */
628 u32 min = hck * 27;
629 u32 max = hck * 54;
630 u32 temp, best = 0;
631 u32 i, j, max_pred = 8, max_postd = 8, pred = 1, postd = 1;
632 u32 pll_div, pll_num, pll_denom, post_div = 1;
633
634 debug("mxs_set_lcdclk, freq = %dKHz\n", freq);
635
Peng Fan7e2e2092016-12-11 19:24:29 +0800636 if (!is_mx6sx() && !is_mx6ul() && !is_mx6ull() && !is_mx6sl() &&
637 !is_mx6sll()) {
Peng Fan53ebda82015-10-29 15:54:47 +0800638 debug("This chip not support lcd!\n");
639 return;
640 }
641
Peng Fan9fa509a2016-12-11 19:24:27 +0800642 if (!is_mx6sl()) {
643 if (base_addr == LCDIF1_BASE_ADDR) {
644 reg = readl(&imx_ccm->cscdr2);
645 /* Can't change clocks when clock not from pre-mux */
646 if ((reg & MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK) != 0)
647 return;
648 }
Peng Fan53ebda82015-10-29 15:54:47 +0800649 }
650
Peng Fan6861c5a2016-05-23 18:35:54 +0800651 if (is_mx6sx()) {
Peng Fan53ebda82015-10-29 15:54:47 +0800652 reg = readl(&imx_ccm->cscdr2);
653 /* Can't change clocks when clock not from pre-mux */
654 if ((reg & MXC_CCM_CSCDR2_LCDIF2_CLK_SEL_MASK) != 0)
655 return;
656 }
657
658 temp = freq * max_pred * max_postd;
Peng Fan53ebda82015-10-29 15:54:47 +0800659 if (temp < min) {
660 /*
661 * Register: PLL_VIDEO
662 * Bit Field: POST_DIV_SELECT
663 * 00 — Divide by 4.
664 * 01 — Divide by 2.
665 * 10 — Divide by 1.
666 * 11 — Reserved
667 * No need to check post_div(1)
668 */
669 for (post_div = 2; post_div <= 4; post_div <<= 1) {
670 if ((temp * post_div) > min) {
671 freq *= post_div;
672 break;
673 }
674 }
675
676 if (post_div > 4) {
677 printf("Fail to set rate to %dkhz", freq);
678 return;
679 }
680 }
681
682 /* Choose the best pred and postd to match freq for lcd */
683 for (i = 1; i <= max_pred; i++) {
684 for (j = 1; j <= max_postd; j++) {
685 temp = freq * i * j;
686 if (temp > max || temp < min)
687 continue;
688 if (best == 0 || temp < best) {
689 best = temp;
690 pred = i;
691 postd = j;
692 }
693 }
694 }
695
696 if (best == 0) {
697 printf("Fail to set rate to %dKHz", freq);
698 return;
699 }
700
701 debug("best %d, pred = %d, postd = %d\n", best, pred, postd);
702
703 pll_div = best / hck;
704 pll_denom = 1000000;
705 pll_num = (best - hck * pll_div) * pll_denom / hck;
706
707 /*
708 * pll_num
709 * (24MHz * (pll_div + --------- ))
710 * pll_denom
711 *freq KHz = --------------------------------
712 * post_div * pred * postd * 1000
713 */
714
715 if (base_addr == LCDIF1_BASE_ADDR) {
716 if (enable_pll_video(pll_div, pll_num, pll_denom, post_div))
717 return;
718
Peng Fan4bbd7422016-12-11 19:24:28 +0800719 enable_lcdif_clock(base_addr, 0);
Peng Fan9fa509a2016-12-11 19:24:27 +0800720 if (!is_mx6sl()) {
721 /* Select pre-lcd clock to PLL5 and set pre divider */
722 clrsetbits_le32(&imx_ccm->cscdr2,
723 MXC_CCM_CSCDR2_LCDIF1_PRED_SEL_MASK |
724 MXC_CCM_CSCDR2_LCDIF1_PRE_DIV_MASK,
725 (0x2 << MXC_CCM_CSCDR2_LCDIF1_PRED_SEL_OFFSET) |
726 ((pred - 1) <<
727 MXC_CCM_CSCDR2_LCDIF1_PRE_DIV_OFFSET));
Peng Fan53ebda82015-10-29 15:54:47 +0800728
Peng Fan9fa509a2016-12-11 19:24:27 +0800729 /* Set the post divider */
730 clrsetbits_le32(&imx_ccm->cbcmr,
731 MXC_CCM_CBCMR_LCDIF1_PODF_MASK,
732 ((postd - 1) <<
733 MXC_CCM_CBCMR_LCDIF1_PODF_OFFSET));
734 } else {
735 /* Select pre-lcd clock to PLL5 and set pre divider */
736 clrsetbits_le32(&imx_ccm->cscdr2,
737 MXC_CCM_CSCDR2_LCDIF_PIX_CLK_SEL_MASK |
738 MXC_CCM_CSCDR2_LCDIF_PIX_PRE_DIV_MASK,
739 (0x2 << MXC_CCM_CSCDR2_LCDIF_PIX_CLK_SEL_OFFSET) |
740 ((pred - 1) <<
741 MXC_CCM_CSCDR2_LCDIF_PIX_PRE_DIV_OFFSET));
742
743 /* Set the post divider */
744 clrsetbits_le32(&imx_ccm->cscmr1,
745 MXC_CCM_CSCMR1_LCDIF_PIX_PODF_MASK,
746 (((postd - 1)^0x6) <<
747 MXC_CCM_CSCMR1_LCDIF_PIX_PODF_OFFSET));
748 }
Peng Fan4bbd7422016-12-11 19:24:28 +0800749
750 enable_lcdif_clock(base_addr, 1);
Peng Fan6861c5a2016-05-23 18:35:54 +0800751 } else if (is_mx6sx()) {
Peng Fan53ebda82015-10-29 15:54:47 +0800752 /* Setting LCDIF2 for i.MX6SX */
753 if (enable_pll_video(pll_div, pll_num, pll_denom, post_div))
754 return;
755
Peng Fan4bbd7422016-12-11 19:24:28 +0800756 enable_lcdif_clock(base_addr, 0);
Peng Fan53ebda82015-10-29 15:54:47 +0800757 /* Select pre-lcd clock to PLL5 and set pre divider */
758 clrsetbits_le32(&imx_ccm->cscdr2,
759 MXC_CCM_CSCDR2_LCDIF2_PRED_SEL_MASK |
760 MXC_CCM_CSCDR2_LCDIF2_PRE_DIV_MASK,
761 (0x2 << MXC_CCM_CSCDR2_LCDIF2_PRED_SEL_OFFSET) |
762 ((pred - 1) <<
763 MXC_CCM_CSCDR2_LCDIF2_PRE_DIV_OFFSET));
764
765 /* Set the post divider */
766 clrsetbits_le32(&imx_ccm->cscmr1,
767 MXC_CCM_CSCMR1_LCDIF2_PODF_MASK,
768 ((postd - 1) <<
769 MXC_CCM_CSCMR1_LCDIF2_PODF_OFFSET));
Peng Fan4bbd7422016-12-11 19:24:28 +0800770
771 enable_lcdif_clock(base_addr, 1);
Peng Fan53ebda82015-10-29 15:54:47 +0800772 }
773}
774
Peng Fan4bbd7422016-12-11 19:24:28 +0800775int enable_lcdif_clock(u32 base_addr, bool enable)
Peng Fan53ebda82015-10-29 15:54:47 +0800776{
777 u32 reg = 0;
778 u32 lcdif_clk_sel_mask, lcdif_ccgr3_mask;
779
Peng Fan6861c5a2016-05-23 18:35:54 +0800780 if (is_mx6sx()) {
Ye Lie9534c32016-01-26 22:01:57 +0800781 if ((base_addr != LCDIF1_BASE_ADDR) &&
782 (base_addr != LCDIF2_BASE_ADDR)) {
Peng Fan53ebda82015-10-29 15:54:47 +0800783 puts("Wrong LCD interface!\n");
784 return -EINVAL;
785 }
786 /* Set to pre-mux clock at default */
787 lcdif_clk_sel_mask = (base_addr == LCDIF2_BASE_ADDR) ?
788 MXC_CCM_CSCDR2_LCDIF2_CLK_SEL_MASK :
789 MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK;
790 lcdif_ccgr3_mask = (base_addr == LCDIF2_BASE_ADDR) ?
791 (MXC_CCM_CCGR3_LCDIF2_PIX_MASK |
792 MXC_CCM_CCGR3_DISP_AXI_MASK) :
793 (MXC_CCM_CCGR3_LCDIF1_PIX_MASK |
794 MXC_CCM_CCGR3_DISP_AXI_MASK);
Peng Fan7e2e2092016-12-11 19:24:29 +0800795 } else if (is_mx6ul() || is_mx6ull() || is_mx6sll()) {
Peng Fan53ebda82015-10-29 15:54:47 +0800796 if (base_addr != LCDIF1_BASE_ADDR) {
797 puts("Wrong LCD interface!\n");
798 return -EINVAL;
799 }
800 /* Set to pre-mux clock at default */
801 lcdif_clk_sel_mask = MXC_CCM_CSCDR2_LCDIF1_CLK_SEL_MASK;
802 lcdif_ccgr3_mask = MXC_CCM_CCGR3_LCDIF1_PIX_MASK;
Peng Fan9fa509a2016-12-11 19:24:27 +0800803 } else if (is_mx6sl()) {
804 if (base_addr != LCDIF1_BASE_ADDR) {
805 puts("Wrong LCD interface!\n");
806 return -EINVAL;
807 }
808
809 reg = readl(&imx_ccm->CCGR3);
810 reg &= ~(MXC_CCM_CCGR3_LCDIF_AXI_MASK |
811 MXC_CCM_CCGR3_LCDIF_PIX_MASK);
812 writel(reg, &imx_ccm->CCGR3);
813
Peng Fan4bbd7422016-12-11 19:24:28 +0800814 if (enable) {
815 reg = readl(&imx_ccm->cscdr3);
816 reg &= ~MXC_CCM_CSCDR3_LCDIF_AXI_CLK_SEL_MASK;
817 reg |= 1 << MXC_CCM_CSCDR3_LCDIF_AXI_CLK_SEL_OFFSET;
818 writel(reg, &imx_ccm->cscdr3);
Peng Fan9fa509a2016-12-11 19:24:27 +0800819
Peng Fan4bbd7422016-12-11 19:24:28 +0800820 reg = readl(&imx_ccm->CCGR3);
821 reg |= MXC_CCM_CCGR3_LCDIF_AXI_MASK |
822 MXC_CCM_CCGR3_LCDIF_PIX_MASK;
823 writel(reg, &imx_ccm->CCGR3);
824 }
Peng Fan9fa509a2016-12-11 19:24:27 +0800825
826 return 0;
Peng Fan53ebda82015-10-29 15:54:47 +0800827 } else {
828 return 0;
829 }
830
Peng Fan690fb4e2016-12-11 19:24:26 +0800831 /* Gate LCDIF clock first */
832 reg = readl(&imx_ccm->CCGR3);
833 reg &= ~lcdif_ccgr3_mask;
834 writel(reg, &imx_ccm->CCGR3);
835
836 reg = readl(&imx_ccm->CCGR2);
837 reg &= ~MXC_CCM_CCGR2_LCD_MASK;
838 writel(reg, &imx_ccm->CCGR2);
839
Peng Fan4bbd7422016-12-11 19:24:28 +0800840 if (enable) {
841 /* Select pre-mux */
842 reg = readl(&imx_ccm->cscdr2);
843 reg &= ~lcdif_clk_sel_mask;
844 writel(reg, &imx_ccm->cscdr2);
Peng Fan53ebda82015-10-29 15:54:47 +0800845
Peng Fan4bbd7422016-12-11 19:24:28 +0800846 /* Enable the LCDIF pix clock */
847 reg = readl(&imx_ccm->CCGR3);
848 reg |= lcdif_ccgr3_mask;
849 writel(reg, &imx_ccm->CCGR3);
Peng Fan53ebda82015-10-29 15:54:47 +0800850
Peng Fan4bbd7422016-12-11 19:24:28 +0800851 reg = readl(&imx_ccm->CCGR2);
852 reg |= MXC_CCM_CCGR2_LCD_MASK;
853 writel(reg, &imx_ccm->CCGR2);
854 }
Jeroen Hofsteeb1a4ac62015-11-29 18:30:34 +0100855
856 return 0;
Peng Fan53ebda82015-10-29 15:54:47 +0800857}
858#endif
859
Peng Fan40a6ed12015-07-20 19:28:27 +0800860#ifdef CONFIG_FSL_QSPI
Peng Fan828e4682014-12-31 11:01:38 +0800861/* qspi_num can be from 0 - 1 */
862void enable_qspi_clk(int qspi_num)
863{
864 u32 reg = 0;
865 /* Enable QuadSPI clock */
866 switch (qspi_num) {
867 case 0:
868 /* disable the clock gate */
869 clrbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK);
870
871 /* set 50M : (50 = 396 / 2 / 4) */
872 reg = readl(&imx_ccm->cscmr1);
873 reg &= ~(MXC_CCM_CSCMR1_QSPI1_PODF_MASK |
874 MXC_CCM_CSCMR1_QSPI1_CLK_SEL_MASK);
875 reg |= ((1 << MXC_CCM_CSCMR1_QSPI1_PODF_OFFSET) |
876 (2 << MXC_CCM_CSCMR1_QSPI1_CLK_SEL_OFFSET));
877 writel(reg, &imx_ccm->cscmr1);
878
879 /* enable the clock gate */
880 setbits_le32(&imx_ccm->CCGR3, MXC_CCM_CCGR3_QSPI1_MASK);
881 break;
882 case 1:
883 /*
884 * disable the clock gate
885 * QSPI2 and GPMI_BCH_INPUT_GPMI_IO share the same clock gate,
886 * disable both of them.
887 */
888 clrbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK |
889 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK);
890
891 /* set 50M : (50 = 396 / 2 / 4) */
892 reg = readl(&imx_ccm->cs2cdr);
893 reg &= ~(MXC_CCM_CS2CDR_QSPI2_CLK_PODF_MASK |
894 MXC_CCM_CS2CDR_QSPI2_CLK_PRED_MASK |
895 MXC_CCM_CS2CDR_QSPI2_CLK_SEL_MASK);
896 reg |= (MXC_CCM_CS2CDR_QSPI2_CLK_PRED(0x1) |
897 MXC_CCM_CS2CDR_QSPI2_CLK_SEL(0x3));
898 writel(reg, &imx_ccm->cs2cdr);
899
900 /*enable the clock gate*/
901 setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_QSPI2_ENFC_MASK |
902 MXC_CCM_CCGR4_RAWNAND_U_GPMI_BCH_INPUT_GPMI_IO_MASK);
903 break;
904 default:
905 break;
906 }
907}
908#endif
909
Otavio Salvadordc074432013-12-16 20:44:05 -0200910#ifdef CONFIG_FEC_MXC
Peng Fan967a83b2015-08-12 17:46:50 +0800911int enable_fec_anatop_clock(int fec_id, enum enet_freq freq)
Fabio Estevam67b8b9d2013-09-13 00:36:28 -0300912{
913 u32 reg = 0;
914 s32 timeout = 100000;
915
916 struct anatop_regs __iomem *anatop =
917 (struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
918
Stefan Roesed7e07312014-11-27 13:46:43 +0100919 if (freq < ENET_25MHZ || freq > ENET_125MHZ)
Fabio Estevamb2903ae2014-01-03 15:55:57 -0200920 return -EINVAL;
921
Peng Fanf868f9f2015-09-06 17:15:47 +0800922 reg = readl(&anatop->pll_enet);
923
Peng Fan967a83b2015-08-12 17:46:50 +0800924 if (fec_id == 0) {
925 reg &= ~BM_ANADIG_PLL_ENET_DIV_SELECT;
926 reg |= BF_ANADIG_PLL_ENET_DIV_SELECT(freq);
927 } else if (fec_id == 1) {
928 /* Only i.MX6SX/UL support ENET2 */
Peng Fance7a7122016-08-11 14:02:47 +0800929 if (!(is_mx6sx() || is_mx6ul() || is_mx6ull()))
Peng Fan967a83b2015-08-12 17:46:50 +0800930 return -EINVAL;
931 reg &= ~BM_ANADIG_PLL_ENET2_DIV_SELECT;
932 reg |= BF_ANADIG_PLL_ENET2_DIV_SELECT(freq);
933 } else {
934 return -EINVAL;
935 }
Fabio Estevamb2903ae2014-01-03 15:55:57 -0200936
Fabio Estevam67b8b9d2013-09-13 00:36:28 -0300937 if ((reg & BM_ANADIG_PLL_ENET_POWERDOWN) ||
938 (!(reg & BM_ANADIG_PLL_ENET_LOCK))) {
939 reg &= ~BM_ANADIG_PLL_ENET_POWERDOWN;
940 writel(reg, &anatop->pll_enet);
941 while (timeout--) {
942 if (readl(&anatop->pll_enet) & BM_ANADIG_PLL_ENET_LOCK)
943 break;
944 }
945 if (timeout < 0)
946 return -ETIMEDOUT;
947 }
948
949 /* Enable FEC clock */
Peng Fan967a83b2015-08-12 17:46:50 +0800950 if (fec_id == 0)
951 reg |= BM_ANADIG_PLL_ENET_ENABLE;
952 else
953 reg |= BM_ANADIG_PLL_ENET2_ENABLE;
Fabio Estevam67b8b9d2013-09-13 00:36:28 -0300954 reg &= ~BM_ANADIG_PLL_ENET_BYPASS;
955 writel(reg, &anatop->pll_enet);
956
Fabio Estevamd4d60382014-08-15 00:24:30 -0300957#ifdef CONFIG_MX6SX
Ye.Lie91df612016-10-08 16:58:29 +0800958 /* Disable enet system clcok before switching clock parent */
959 reg = readl(&imx_ccm->CCGR3);
960 reg &= ~MXC_CCM_CCGR3_ENET_MASK;
961 writel(reg, &imx_ccm->CCGR3);
962
Fabio Estevamd4d60382014-08-15 00:24:30 -0300963 /*
964 * Set enet ahb clock to 200MHz
965 * pll2_pfd2_396m-> ENET_PODF-> ENET_AHB
966 */
967 reg = readl(&imx_ccm->chsccdr);
968 reg &= ~(MXC_CCM_CHSCCDR_ENET_PRE_CLK_SEL_MASK
969 | MXC_CCM_CHSCCDR_ENET_PODF_MASK
970 | MXC_CCM_CHSCCDR_ENET_CLK_SEL_MASK);
971 /* PLL2 PFD2 */
972 reg |= (4 << MXC_CCM_CHSCCDR_ENET_PRE_CLK_SEL_OFFSET);
973 /* Div = 2*/
974 reg |= (1 << MXC_CCM_CHSCCDR_ENET_PODF_OFFSET);
975 reg |= (0 << MXC_CCM_CHSCCDR_ENET_CLK_SEL_OFFSET);
976 writel(reg, &imx_ccm->chsccdr);
977
978 /* Enable enet system clock */
979 reg = readl(&imx_ccm->CCGR3);
980 reg |= MXC_CCM_CCGR3_ENET_MASK;
981 writel(reg, &imx_ccm->CCGR3);
982#endif
Fabio Estevam67b8b9d2013-09-13 00:36:28 -0300983 return 0;
984}
Fabio Estevamf7b9ac22013-04-10 09:32:57 +0000985#endif
Jason Liudec11122011-11-25 00:18:02 +0000986
987static u32 get_usdhc_clk(u32 port)
988{
989 u32 root_freq = 0, usdhc_podf = 0, clk_sel = 0;
990 u32 cscmr1 = __raw_readl(&imx_ccm->cscmr1);
991 u32 cscdr1 = __raw_readl(&imx_ccm->cscdr1);
992
Peng Fan7e2e2092016-12-11 19:24:29 +0800993 if (is_mx6ul() || is_mx6ull()) {
994 if (port > 1)
995 return 0;
996 }
997
998 if (is_mx6sll()) {
999 if (port > 2)
1000 return 0;
1001 }
1002
Jason Liudec11122011-11-25 00:18:02 +00001003 switch (port) {
1004 case 0:
1005 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC1_PODF_MASK) >>
1006 MXC_CCM_CSCDR1_USDHC1_PODF_OFFSET;
1007 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC1_CLK_SEL;
1008
1009 break;
1010 case 1:
1011 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC2_PODF_MASK) >>
1012 MXC_CCM_CSCDR1_USDHC2_PODF_OFFSET;
1013 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC2_CLK_SEL;
1014
1015 break;
1016 case 2:
1017 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC3_PODF_MASK) >>
1018 MXC_CCM_CSCDR1_USDHC3_PODF_OFFSET;
1019 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC3_CLK_SEL;
1020
1021 break;
1022 case 3:
1023 usdhc_podf = (cscdr1 & MXC_CCM_CSCDR1_USDHC4_PODF_MASK) >>
1024 MXC_CCM_CSCDR1_USDHC4_PODF_OFFSET;
1025 clk_sel = cscmr1 & MXC_CCM_CSCMR1_USDHC4_CLK_SEL;
1026
1027 break;
1028 default:
1029 break;
1030 }
1031
1032 if (clk_sel)
Pierre Auberte8e62a72013-09-19 17:48:59 +02001033 root_freq = mxc_get_pll_pfd(PLL_BUS, 0);
Jason Liudec11122011-11-25 00:18:02 +00001034 else
Pierre Auberte8e62a72013-09-19 17:48:59 +02001035 root_freq = mxc_get_pll_pfd(PLL_BUS, 2);
Jason Liudec11122011-11-25 00:18:02 +00001036
1037 return root_freq / (usdhc_podf + 1);
1038}
1039
1040u32 imx_get_uartclk(void)
1041{
1042 return get_uart_clk();
1043}
1044
Jason Liu92aa90b2011-12-16 05:17:06 +00001045u32 imx_get_fecclk(void)
1046{
Markus Niebel6c109b82014-02-05 10:51:25 +01001047 return mxc_get_clock(MXC_IPG_CLK);
Jason Liu92aa90b2011-12-16 05:17:06 +00001048}
1049
Simon Glassab3055a2017-06-14 21:28:25 -06001050#if defined(CONFIG_SATA) || defined(CONFIG_PCIE_IMX)
Marek Vasut563dfb22013-12-14 06:27:26 +01001051static int enable_enet_pll(uint32_t en)
Eric Nelsonfdba0762012-03-27 09:52:21 +00001052{
Eric Nelsonfdba0762012-03-27 09:52:21 +00001053 struct mxc_ccm_reg *const imx_ccm
1054 = (struct mxc_ccm_reg *) CCM_BASE_ADDR;
Marek Vasut563dfb22013-12-14 06:27:26 +01001055 s32 timeout = 100000;
1056 u32 reg = 0;
Eric Nelsonfdba0762012-03-27 09:52:21 +00001057
1058 /* Enable PLLs */
1059 reg = readl(&imx_ccm->analog_pll_enet);
1060 reg &= ~BM_ANADIG_PLL_SYS_POWERDOWN;
1061 writel(reg, &imx_ccm->analog_pll_enet);
1062 reg |= BM_ANADIG_PLL_SYS_ENABLE;
1063 while (timeout--) {
1064 if (readl(&imx_ccm->analog_pll_enet) & BM_ANADIG_PLL_SYS_LOCK)
1065 break;
1066 }
1067 if (timeout <= 0)
1068 return -EIO;
1069 reg &= ~BM_ANADIG_PLL_SYS_BYPASS;
1070 writel(reg, &imx_ccm->analog_pll_enet);
Marek Vasut563dfb22013-12-14 06:27:26 +01001071 reg |= en;
Eric Nelsonfdba0762012-03-27 09:52:21 +00001072 writel(reg, &imx_ccm->analog_pll_enet);
Marek Vasut563dfb22013-12-14 06:27:26 +01001073 return 0;
1074}
Peng Fan40a6ed12015-07-20 19:28:27 +08001075#endif
Marek Vasut563dfb22013-12-14 06:27:26 +01001076
Simon Glassab3055a2017-06-14 21:28:25 -06001077#ifdef CONFIG_SATA
Marek Vasut563dfb22013-12-14 06:27:26 +01001078static void ungate_sata_clock(void)
1079{
1080 struct mxc_ccm_reg *const imx_ccm =
1081 (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1082
1083 /* Enable SATA clock. */
1084 setbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK);
1085}
1086
Marek Vasut563dfb22013-12-14 06:27:26 +01001087int enable_sata_clock(void)
1088{
1089 ungate_sata_clock();
1090 return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA);
1091}
Nikita Kiryanov63659b72014-11-21 12:47:22 +02001092
1093void disable_sata_clock(void)
1094{
1095 struct mxc_ccm_reg *const imx_ccm =
1096 (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1097
1098 clrbits_le32(&imx_ccm->CCGR5, MXC_CCM_CCGR5_SATA_MASK);
1099}
Fabio Estevam15af7332014-06-24 17:41:00 -03001100#endif
Marek Vasut563dfb22013-12-14 06:27:26 +01001101
Peng Fan40a6ed12015-07-20 19:28:27 +08001102#ifdef CONFIG_PCIE_IMX
1103static void ungate_pcie_clock(void)
1104{
1105 struct mxc_ccm_reg *const imx_ccm =
1106 (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1107
1108 /* Enable PCIe clock. */
1109 setbits_le32(&imx_ccm->CCGR4, MXC_CCM_CCGR4_PCIE_MASK);
1110}
1111
Marek Vasut563dfb22013-12-14 06:27:26 +01001112int enable_pcie_clock(void)
1113{
1114 struct anatop_regs *anatop_regs =
1115 (struct anatop_regs *)ANATOP_BASE_ADDR;
1116 struct mxc_ccm_reg *ccm_regs = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
Fabio Estevam211a4902014-08-25 14:26:45 -03001117 u32 lvds1_clk_sel;
Marek Vasut563dfb22013-12-14 06:27:26 +01001118
1119 /*
1120 * Here be dragons!
1121 *
1122 * The register ANATOP_MISC1 is not documented in the Freescale
1123 * MX6RM. The register that is mapped in the ANATOP space and
1124 * marked as ANATOP_MISC1 is actually documented in the PMU section
1125 * of the datasheet as PMU_MISC1.
1126 *
Fabio Estevam211a4902014-08-25 14:26:45 -03001127 * Switch LVDS clock source to SATA (0xb) on mx6q/dl or PCI (0xa) on
1128 * mx6sx, disable clock INPUT and enable clock OUTPUT. This is important
1129 * for PCI express link that is clocked from the i.MX6.
Marek Vasut563dfb22013-12-14 06:27:26 +01001130 */
1131#define ANADIG_ANA_MISC1_LVDSCLK1_IBEN (1 << 12)
1132#define ANADIG_ANA_MISC1_LVDSCLK1_OBEN (1 << 10)
1133#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK 0x0000001F
Fabio Estevam211a4902014-08-25 14:26:45 -03001134#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_PCIE_REF 0xa
1135#define ANADIG_ANA_MISC1_LVDS1_CLK_SEL_SATA_REF 0xb
1136
Peng Fan6861c5a2016-05-23 18:35:54 +08001137 if (is_mx6sx())
Fabio Estevam211a4902014-08-25 14:26:45 -03001138 lvds1_clk_sel = ANADIG_ANA_MISC1_LVDS1_CLK_SEL_PCIE_REF;
1139 else
1140 lvds1_clk_sel = ANADIG_ANA_MISC1_LVDS1_CLK_SEL_SATA_REF;
1141
Marek Vasut563dfb22013-12-14 06:27:26 +01001142 clrsetbits_le32(&anatop_regs->ana_misc1,
1143 ANADIG_ANA_MISC1_LVDSCLK1_IBEN |
1144 ANADIG_ANA_MISC1_LVDS1_CLK_SEL_MASK,
Fabio Estevam211a4902014-08-25 14:26:45 -03001145 ANADIG_ANA_MISC1_LVDSCLK1_OBEN | lvds1_clk_sel);
Marek Vasut563dfb22013-12-14 06:27:26 +01001146
1147 /* PCIe reference clock sourced from AXI. */
1148 clrbits_le32(&ccm_regs->cbcmr, MXC_CCM_CBCMR_PCIE_AXI_CLK_SEL);
1149
1150 /* Party time! Ungate the clock to the PCIe. */
Simon Glassab3055a2017-06-14 21:28:25 -06001151#ifdef CONFIG_SATA
Marek Vasut563dfb22013-12-14 06:27:26 +01001152 ungate_sata_clock();
Fabio Estevam15af7332014-06-24 17:41:00 -03001153#endif
Marek Vasut563dfb22013-12-14 06:27:26 +01001154 ungate_pcie_clock();
Eric Nelsonfdba0762012-03-27 09:52:21 +00001155
Marek Vasut563dfb22013-12-14 06:27:26 +01001156 return enable_enet_pll(BM_ANADIG_PLL_ENET_ENABLE_SATA |
1157 BM_ANADIG_PLL_ENET_ENABLE_PCIE);
Eric Nelsonfdba0762012-03-27 09:52:21 +00001158}
Peng Fan40a6ed12015-07-20 19:28:27 +08001159#endif
Eric Nelsonfdba0762012-03-27 09:52:21 +00001160
Stefano Babicf8b509b2019-09-20 08:47:53 +02001161#ifdef CONFIG_IMX_HAB
Nitin Gargb1ce7012014-09-16 13:33:25 -05001162void hab_caam_clock_enable(unsigned char enable)
1163{
1164 u32 reg;
1165
Peng Fan7e2e2092016-12-11 19:24:29 +08001166 if (is_mx6ull() || is_mx6sll()) {
Peng Fance7a7122016-08-11 14:02:47 +08001167 /* CG5, DCP clock */
1168 reg = __raw_readl(&imx_ccm->CCGR0);
1169 if (enable)
1170 reg |= MXC_CCM_CCGR0_DCP_CLK_MASK;
1171 else
1172 reg &= ~MXC_CCM_CCGR0_DCP_CLK_MASK;
1173 __raw_writel(reg, &imx_ccm->CCGR0);
1174 } else {
1175 /* CG4 ~ CG6, CAAM clocks */
1176 reg = __raw_readl(&imx_ccm->CCGR0);
1177 if (enable)
1178 reg |= (MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK |
1179 MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK |
1180 MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK);
1181 else
1182 reg &= ~(MXC_CCM_CCGR0_CAAM_WRAPPER_IPG_MASK |
1183 MXC_CCM_CCGR0_CAAM_WRAPPER_ACLK_MASK |
1184 MXC_CCM_CCGR0_CAAM_SECURE_MEM_MASK);
1185 __raw_writel(reg, &imx_ccm->CCGR0);
1186 }
Nitin Gargb1ce7012014-09-16 13:33:25 -05001187
1188 /* EMI slow clk */
1189 reg = __raw_readl(&imx_ccm->CCGR6);
1190 if (enable)
1191 reg |= MXC_CCM_CCGR6_EMI_SLOW_MASK;
1192 else
1193 reg &= ~MXC_CCM_CCGR6_EMI_SLOW_MASK;
1194 __raw_writel(reg, &imx_ccm->CCGR6);
1195}
1196#endif
1197
Nitin Garg59f3be32014-11-20 21:14:12 +08001198static void enable_pll3(void)
1199{
1200 struct anatop_regs __iomem *anatop =
1201 (struct anatop_regs __iomem *)ANATOP_BASE_ADDR;
1202
1203 /* make sure pll3 is enabled */
1204 if ((readl(&anatop->usb1_pll_480_ctrl) &
1205 BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0) {
1206 /* enable pll's power */
1207 writel(BM_ANADIG_USB1_PLL_480_CTRL_POWER,
1208 &anatop->usb1_pll_480_ctrl_set);
1209 writel(0x80, &anatop->ana_misc2_clr);
1210 /* wait for pll lock */
1211 while ((readl(&anatop->usb1_pll_480_ctrl) &
1212 BM_ANADIG_USB1_PLL_480_CTRL_LOCK) == 0)
1213 ;
1214 /* disable bypass */
1215 writel(BM_ANADIG_USB1_PLL_480_CTRL_BYPASS,
1216 &anatop->usb1_pll_480_ctrl_clr);
1217 /* enable pll output */
1218 writel(BM_ANADIG_USB1_PLL_480_CTRL_ENABLE,
1219 &anatop->usb1_pll_480_ctrl_set);
1220 }
1221}
1222
1223void enable_thermal_clk(void)
1224{
1225 enable_pll3();
1226}
1227
Anatolij Gustschin03dd9862017-08-28 21:46:26 +02001228#ifdef CONFIG_MTD_NOR_FLASH
1229void enable_eim_clk(unsigned char enable)
1230{
1231 u32 reg;
1232
1233 reg = __raw_readl(&imx_ccm->CCGR6);
1234 if (enable)
1235 reg |= MXC_CCM_CCGR6_EMI_SLOW_MASK;
1236 else
1237 reg &= ~MXC_CCM_CCGR6_EMI_SLOW_MASK;
1238 __raw_writel(reg, &imx_ccm->CCGR6);
1239}
1240#endif
1241
Jason Liudec11122011-11-25 00:18:02 +00001242unsigned int mxc_get_clock(enum mxc_clock clk)
1243{
1244 switch (clk) {
1245 case MXC_ARM_CLK:
1246 return get_mcu_main_clk();
1247 case MXC_PER_CLK:
1248 return get_periph_clk();
1249 case MXC_AHB_CLK:
1250 return get_ahb_clk();
1251 case MXC_IPG_CLK:
1252 return get_ipg_clk();
1253 case MXC_IPG_PERCLK:
Matthias Weisser99ba3422012-09-24 02:46:53 +00001254 case MXC_I2C_CLK:
Jason Liudec11122011-11-25 00:18:02 +00001255 return get_ipg_per_clk();
1256 case MXC_UART_CLK:
1257 return get_uart_clk();
1258 case MXC_CSPI_CLK:
1259 return get_cspi_clk();
1260 case MXC_AXI_CLK:
1261 return get_axi_clk();
1262 case MXC_EMI_SLOW_CLK:
1263 return get_emi_slow_clk();
1264 case MXC_DDR_CLK:
1265 return get_mmdc_ch0_clk();
1266 case MXC_ESDHC_CLK:
1267 return get_usdhc_clk(0);
1268 case MXC_ESDHC2_CLK:
1269 return get_usdhc_clk(1);
1270 case MXC_ESDHC3_CLK:
1271 return get_usdhc_clk(2);
1272 case MXC_ESDHC4_CLK:
1273 return get_usdhc_clk(3);
1274 case MXC_SATA_CLK:
1275 return get_ahb_clk();
1276 default:
Peng Fan3c7cb492014-11-23 11:52:20 +08001277 printf("Unsupported MXC CLK: %d\n", clk);
Jason Liudec11122011-11-25 00:18:02 +00001278 break;
1279 }
1280
Peng Fan3c7cb492014-11-23 11:52:20 +08001281 return 0;
Jason Liudec11122011-11-25 00:18:02 +00001282}
1283
Fabio Estevamb4072fa2019-07-12 09:10:35 -03001284#ifndef CONFIG_MX6SX
1285void enable_ipu_clock(void)
1286{
1287 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
Fabio Estevam927d54b2019-07-12 09:32:22 -03001288
1289 setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU1_IPU_MASK);
Fabio Estevamb4072fa2019-07-12 09:10:35 -03001290
1291 if (is_mx6dqp()) {
1292 setbits_le32(&mxc_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
1293 setbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
1294 }
1295}
Fabio Estevam1b6c50e2019-07-12 09:32:23 -03001296
1297void disable_ipu_clock(void)
1298{
1299 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1300
1301 clrbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU1_IPU_MASK);
1302
1303 if (is_mx6dqp()) {
1304 clrbits_le32(&mxc_ccm->CCGR6, MXC_CCM_CCGR6_PRG_CLK0_MASK);
1305 clrbits_le32(&mxc_ccm->CCGR3, MXC_CCM_CCGR3_IPU2_IPU_MASK);
1306 }
1307}
Fabio Estevamb4072fa2019-07-12 09:10:35 -03001308#endif
1309
Anatolij Gustschin03dd9862017-08-28 21:46:26 +02001310#ifndef CONFIG_SPL_BUILD
Jason Liudec11122011-11-25 00:18:02 +00001311/*
1312 * Dump some core clockes.
1313 */
Simon Glassed38aef2020-05-10 11:40:03 -06001314int do_mx6_showclocks(struct cmd_tbl *cmdtp, int flag, int argc,
1315 char *const argv[])
Jason Liudec11122011-11-25 00:18:02 +00001316{
1317 u32 freq;
Benoît Thébaudeauafac1652012-09-27 10:19:58 +00001318 freq = decode_pll(PLL_SYS, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +00001319 printf("PLL_SYS %8d MHz\n", freq / 1000000);
Benoît Thébaudeauafac1652012-09-27 10:19:58 +00001320 freq = decode_pll(PLL_BUS, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +00001321 printf("PLL_BUS %8d MHz\n", freq / 1000000);
Benoît Thébaudeauafac1652012-09-27 10:19:58 +00001322 freq = decode_pll(PLL_USBOTG, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +00001323 printf("PLL_OTG %8d MHz\n", freq / 1000000);
Benoît Thébaudeauafac1652012-09-27 10:19:58 +00001324 freq = decode_pll(PLL_ENET, MXC_HCLK);
Jason Liudec11122011-11-25 00:18:02 +00001325 printf("PLL_NET %8d MHz\n", freq / 1000000);
1326
1327 printf("\n");
Peng Fan219e8c82016-03-09 16:44:38 +08001328 printf("ARM %8d kHz\n", mxc_get_clock(MXC_ARM_CLK) / 1000);
Jason Liudec11122011-11-25 00:18:02 +00001329 printf("IPG %8d kHz\n", mxc_get_clock(MXC_IPG_CLK) / 1000);
1330 printf("UART %8d kHz\n", mxc_get_clock(MXC_UART_CLK) / 1000);
Fabio Estevamf6fde412012-11-16 01:30:10 +00001331#ifdef CONFIG_MXC_SPI
Jason Liudec11122011-11-25 00:18:02 +00001332 printf("CSPI %8d kHz\n", mxc_get_clock(MXC_CSPI_CLK) / 1000);
Fabio Estevamf6fde412012-11-16 01:30:10 +00001333#endif
Jason Liudec11122011-11-25 00:18:02 +00001334 printf("AHB %8d kHz\n", mxc_get_clock(MXC_AHB_CLK) / 1000);
1335 printf("AXI %8d kHz\n", mxc_get_clock(MXC_AXI_CLK) / 1000);
1336 printf("DDR %8d kHz\n", mxc_get_clock(MXC_DDR_CLK) / 1000);
1337 printf("USDHC1 %8d kHz\n", mxc_get_clock(MXC_ESDHC_CLK) / 1000);
1338 printf("USDHC2 %8d kHz\n", mxc_get_clock(MXC_ESDHC2_CLK) / 1000);
1339 printf("USDHC3 %8d kHz\n", mxc_get_clock(MXC_ESDHC3_CLK) / 1000);
1340 printf("USDHC4 %8d kHz\n", mxc_get_clock(MXC_ESDHC4_CLK) / 1000);
1341 printf("EMI SLOW %8d kHz\n", mxc_get_clock(MXC_EMI_SLOW_CLK) / 1000);
1342 printf("IPG PERCLK %8d kHz\n", mxc_get_clock(MXC_IPG_PERCLK) / 1000);
1343
1344 return 0;
1345}
1346
Akshay Bhat4e364e62016-04-12 18:13:56 -04001347#if defined(CONFIG_MX6Q) || defined(CONFIG_MX6D) || defined(CONFIG_MX6DL) || \
Sebastian Reicheleaa9c5b2020-09-02 19:31:41 +02001348 defined(CONFIG_MX6S) || defined(CONFIG_MX6QDL)
Akshay Bhat4e364e62016-04-12 18:13:56 -04001349static void disable_ldb_di_clock_sources(void)
1350{
1351 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1352 int reg;
1353
1354 /* Make sure PFDs are disabled at boot. */
1355 reg = readl(&mxc_ccm->analog_pfd_528);
1356 /* Cannot disable pll2_pfd2_396M, as it is the MMDC clock in iMX6DL */
Peng Fan6861c5a2016-05-23 18:35:54 +08001357 if (is_mx6sdl())
Akshay Bhat4e364e62016-04-12 18:13:56 -04001358 reg |= 0x80008080;
1359 else
1360 reg |= 0x80808080;
1361 writel(reg, &mxc_ccm->analog_pfd_528);
1362
1363 /* Disable PLL3 PFDs */
1364 reg = readl(&mxc_ccm->analog_pfd_480);
1365 reg |= 0x80808080;
1366 writel(reg, &mxc_ccm->analog_pfd_480);
1367
1368 /* Disable PLL5 */
1369 reg = readl(&mxc_ccm->analog_pll_video);
1370 reg &= ~(1 << 13);
1371 writel(reg, &mxc_ccm->analog_pll_video);
1372}
1373
1374static void enable_ldb_di_clock_sources(void)
1375{
1376 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1377 int reg;
1378
1379 reg = readl(&mxc_ccm->analog_pfd_528);
Peng Fan6861c5a2016-05-23 18:35:54 +08001380 if (is_mx6sdl())
Akshay Bhat4e364e62016-04-12 18:13:56 -04001381 reg &= ~(0x80008080);
1382 else
1383 reg &= ~(0x80808080);
1384 writel(reg, &mxc_ccm->analog_pfd_528);
1385
1386 reg = readl(&mxc_ccm->analog_pfd_480);
1387 reg &= ~(0x80808080);
1388 writel(reg, &mxc_ccm->analog_pfd_480);
1389}
1390
1391/*
1392 * Try call this function as early in the boot process as possible since the
1393 * function temporarily disables PLL2 PFD's, PLL3 PFD's and PLL5.
1394 */
1395void select_ldb_di_clock_source(enum ldb_di_clock clk)
1396{
1397 struct mxc_ccm_reg *mxc_ccm = (struct mxc_ccm_reg *)CCM_BASE_ADDR;
1398 int reg;
1399
1400 /*
1401 * Need to follow a strict procedure when changing the LDB
1402 * clock, else we can introduce a glitch. Things to keep in
1403 * mind:
1404 * 1. The current and new parent clocks must be disabled.
1405 * 2. The default clock for ldb_dio_clk is mmdc_ch1 which has
1406 * no CG bit.
1407 * 3. In the RTL implementation of the LDB_DI_CLK_SEL mux
1408 * the top four options are in one mux and the PLL3 option along
1409 * with another option is in the second mux. There is third mux
1410 * used to decide between the first and second mux.
1411 * The code below switches the parent to the bottom mux first
1412 * and then manipulates the top mux. This ensures that no glitch
1413 * will enter the divider.
1414 *
1415 * Need to disable MMDC_CH1 clock manually as there is no CG bit
1416 * for this clock. The only way to disable this clock is to move
1417 * it to pll3_sw_clk and then to disable pll3_sw_clk
1418 * Make sure periph2_clk2_sel is set to pll3_sw_clk
1419 */
1420
1421 /* Disable all ldb_di clock parents */
1422 disable_ldb_di_clock_sources();
1423
1424 /* Set MMDC_CH1 mask bit */
1425 reg = readl(&mxc_ccm->ccdr);
1426 reg |= MXC_CCM_CCDR_MMDC_CH1_HS_MASK;
1427 writel(reg, &mxc_ccm->ccdr);
1428
1429 /* Set periph2_clk2_sel to be sourced from PLL3_sw_clk */
1430 reg = readl(&mxc_ccm->cbcmr);
1431 reg &= ~MXC_CCM_CBCMR_PERIPH2_CLK2_SEL;
1432 writel(reg, &mxc_ccm->cbcmr);
1433
1434 /*
1435 * Set the periph2_clk_sel to the top mux so that
1436 * mmdc_ch1 is from pll3_sw_clk.
1437 */
1438 reg = readl(&mxc_ccm->cbcdr);
1439 reg |= MXC_CCM_CBCDR_PERIPH2_CLK_SEL;
1440 writel(reg, &mxc_ccm->cbcdr);
1441
1442 /* Wait for the clock switch */
1443 while (readl(&mxc_ccm->cdhipr))
1444 ;
1445 /* Disable pll3_sw_clk by selecting bypass clock source */
1446 reg = readl(&mxc_ccm->ccsr);
1447 reg |= MXC_CCM_CCSR_PLL3_SW_CLK_SEL;
1448 writel(reg, &mxc_ccm->ccsr);
1449
1450 /* Set the ldb_di0_clk and ldb_di1_clk to 111b */
1451 reg = readl(&mxc_ccm->cs2cdr);
1452 reg |= ((7 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
1453 | (7 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
1454 writel(reg, &mxc_ccm->cs2cdr);
1455
1456 /* Set the ldb_di0_clk and ldb_di1_clk to 100b */
1457 reg = readl(&mxc_ccm->cs2cdr);
1458 reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK
1459 | MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK);
1460 reg |= ((4 << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
1461 | (4 << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
1462 writel(reg, &mxc_ccm->cs2cdr);
1463
1464 /* Set the ldb_di0_clk and ldb_di1_clk to desired source */
1465 reg = readl(&mxc_ccm->cs2cdr);
1466 reg &= ~(MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_MASK
1467 | MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_MASK);
1468 reg |= ((clk << MXC_CCM_CS2CDR_LDB_DI1_CLK_SEL_OFFSET)
1469 | (clk << MXC_CCM_CS2CDR_LDB_DI0_CLK_SEL_OFFSET));
1470 writel(reg, &mxc_ccm->cs2cdr);
1471
1472 /* Unbypass pll3_sw_clk */
1473 reg = readl(&mxc_ccm->ccsr);
1474 reg &= ~MXC_CCM_CCSR_PLL3_SW_CLK_SEL;
1475 writel(reg, &mxc_ccm->ccsr);
1476
1477 /*
1478 * Set the periph2_clk_sel back to the bottom mux so that
1479 * mmdc_ch1 is from its original parent.
1480 */
1481 reg = readl(&mxc_ccm->cbcdr);
1482 reg &= ~MXC_CCM_CBCDR_PERIPH2_CLK_SEL;
1483 writel(reg, &mxc_ccm->cbcdr);
1484
1485 /* Wait for the clock switch */
1486 while (readl(&mxc_ccm->cdhipr))
1487 ;
1488 /* Clear MMDC_CH1 mask bit */
1489 reg = readl(&mxc_ccm->ccdr);
1490 reg &= ~MXC_CCM_CCDR_MMDC_CH1_HS_MASK;
1491 writel(reg, &mxc_ccm->ccdr);
1492
1493 enable_ldb_di_clock_sources();
1494}
1495#endif
1496
Jason Liudec11122011-11-25 00:18:02 +00001497/***************************************************/
1498
1499U_BOOT_CMD(
1500 clocks, CONFIG_SYS_MAXARGS, 1, do_mx6_showclocks,
1501 "display clocks",
1502 ""
1503);
Anatolij Gustschin03dd9862017-08-28 21:46:26 +02001504#endif