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