1// SPDX-License-Identifier: GPL-2.0+
2/*
3 *
4 * Copyright (C) 2004-2007, 2012 Freescale Semiconductor, Inc.
5 * TsiChung Liew (Tsi-Chung.Liew@freescale.com)
6 */
7
8#include <clock_legacy.h>
9#include <asm/global_data.h>
10#include <asm/processor.h>
11
12#include <asm/immap.h>
13#include <asm/io.h>
14
15DECLARE_GLOBAL_DATA_PTR;
16
17/*
18 * Low Power Divider specifications
19 */
20#define CLOCK_LPD_MIN		(1 << 0)	/* Divider (decoded) */
21#define CLOCK_LPD_MAX		(1 << 15)	/* Divider (decoded) */
22
23#define CLOCK_PLL_FVCO_MAX	540000000
24#define CLOCK_PLL_FVCO_MIN	300000000
25
26#define CLOCK_PLL_FSYS_MAX	266666666
27#define CLOCK_PLL_FSYS_MIN	100000000
28#define MHZ			1000000
29
30void clock_enter_limp(int lpdiv)
31{
32	ccm_t *ccm = (ccm_t *)MMAP_CCM;
33	int i, j;
34
35	/* Check bounds of divider */
36	if (lpdiv < CLOCK_LPD_MIN)
37		lpdiv = CLOCK_LPD_MIN;
38	if (lpdiv > CLOCK_LPD_MAX)
39		lpdiv = CLOCK_LPD_MAX;
40
41	/* Round divider down to nearest power of two */
42	for (i = 0, j = lpdiv; j != 1; j >>= 1, i++) ;
43
44	/* Enable Limp Mode */
45	setbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
46}
47
48/*
49 * brief   Exit Limp mode
50 * warning The PLL should be set and locked prior to exiting Limp mode
51 */
52void clock_exit_limp(void)
53{
54	ccm_t *ccm = (ccm_t *)MMAP_CCM;
55	pll_t *pll = (pll_t *)MMAP_PLL;
56
57	/* Exit Limp mode */
58	clrbits_be16(&ccm->misccr, CCM_MISCCR_LIMP);
59
60	/* Wait for the PLL to lock */
61	while (!(in_be32(&pll->psr) & PLL_PSR_LOCK))
62		;
63}
64
65#ifdef CONFIG_MCF5441x
66void setup_5441x_clocks(void)
67{
68	ccm_t *ccm = (ccm_t *)MMAP_CCM;
69	pll_t *pll = (pll_t *)MMAP_PLL;
70	int temp, vco = 0, bootmod_ccr, pdr;
71
72	bootmod_ccr = (in_be16(&ccm->ccr) & CCM_CCR_BOOTMOD) >> 14;
73
74	switch (bootmod_ccr) {
75	case 0:
76		out_be32(&pll->pcr, 0x00000013);
77		out_be32(&pll->pdr, 0x00e70c61);
78		clock_exit_limp();
79		break;
80	case 2:
81		break;
82	case 3:
83		break;
84	}
85
86	/*Change frequency for Modelo SER1 USB host*/
87#ifdef CONFIG_LOW_MCFCLK
88	temp = in_be32(&pll->pcr);
89	temp &= ~0x3f;
90	temp |= 5;
91	out_be32(&pll->pcr, temp);
92
93	temp = in_be32(&pll->pdr);
94	temp &= ~0x001f0000;
95	temp |= 0x00040000;
96	out_be32(&pll->pdr, temp);
97	__asm__("tpf");
98#endif
99
100	setbits_be16(&ccm->misccr2, 0x02);
101
102	vco =  ((in_be32(&pll->pcr) & PLL_CR_FBKDIV_BITS) + 1) *
103		CONFIG_SYS_INPUT_CLKSRC;
104	gd->arch.vco_clk = vco;
105
106	gd->arch.inp_clk = CONFIG_SYS_INPUT_CLKSRC;	/* Input clock */
107
108	pdr = in_be32(&pll->pdr);
109	temp = (pdr & PLL_DR_OUTDIV1_BITS) + 1;
110	gd->cpu_clk = vco / temp;	/* cpu clock */
111	gd->arch.flb_clk = vco / temp;	/* FlexBus clock */
112	gd->arch.flb_clk >>= 1;
113	if (in_be16(&ccm->misccr2) & 2)		/* fsys/4 */
114		gd->arch.flb_clk >>= 1;
115
116	temp = ((pdr & PLL_DR_OUTDIV2_BITS) >> 5) + 1;
117	gd->bus_clk = vco / temp;	/* bus clock */
118
119	temp = ((pdr & PLL_DR_OUTDIV3_BITS) >> 10) + 1;
120	gd->arch.sdhc_clk = vco / temp;
121}
122#endif
123
124/* get_clocks() fills in gd->cpu_clock and gd->bus_clk */
125int get_clocks(void)
126{
127#ifdef CONFIG_MCF5441x
128	setup_5441x_clocks();
129#endif
130
131	if (IS_ENABLED(CONFIG_SYS_I2C_FSL))
132		gd->arch.i2c1_clk = gd->bus_clk;
133
134	return (0);
135}
136